From 8bd19674084526a534ac11f7d4c51932e9ffe3d2 Mon Sep 17 00:00:00 2001 From: NicJA Date: Thu, 7 Mar 2013 00:43:07 +0000 Subject: [PATCH] w.i.p sdcard device driver for raspi. detects cards but isnt able to send commands which read/write data currently. git-svn-id: https://svn.aros.org/svn/aros/trunk/AROS@46821 fb15a70f-31f2-0310-bbcc-cdcc74a49acc --- arch/arm-raspi/devs/sdcard/mmakefile.src | 9 + arch/arm-raspi/devs/sdcard/sdcard.conf | 42 ++ arch/arm-raspi/devs/sdcard/sdcard_bus.c | 486 ++++++++++++++++++++ arch/arm-raspi/devs/sdcard/sdcard_device.c | 698 +++++++++++++++++++++++++++++ arch/arm-raspi/devs/sdcard/sdcard_init.c | 611 +++++++++++++++++++++++++ arch/arm-raspi/devs/sdcard/sdcard_intern.h | 204 +++++++++ arch/arm-raspi/devs/sdcard/sdcard_ioops.c | 324 +++++++++++++ arch/arm-raspi/devs/sdcard/timer.c | 105 +++++ arch/arm-raspi/devs/sdcard/timer.h | 52 +++ 9 files changed, 2531 insertions(+) create mode 100644 arch/arm-raspi/devs/sdcard/mmakefile.src create mode 100644 arch/arm-raspi/devs/sdcard/sdcard.conf create mode 100644 arch/arm-raspi/devs/sdcard/sdcard_bus.c create mode 100644 arch/arm-raspi/devs/sdcard/sdcard_device.c create mode 100644 arch/arm-raspi/devs/sdcard/sdcard_init.c create mode 100644 arch/arm-raspi/devs/sdcard/sdcard_intern.h create mode 100644 arch/arm-raspi/devs/sdcard/sdcard_ioops.c create mode 100644 arch/arm-raspi/devs/sdcard/timer.c create mode 100644 arch/arm-raspi/devs/sdcard/timer.h diff --git a/arch/arm-raspi/devs/sdcard/mmakefile.src b/arch/arm-raspi/devs/sdcard/mmakefile.src new file mode 100644 index 0000000000..306dfba63f --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/mmakefile.src @@ -0,0 +1,9 @@ +# $Id: mmakefile.src 44918 2012-06-01 03:30:04Z jmcmullan $ +include $(TOP)/config/make.cfg + +USER_CFLAGS += -I $(SRCDIR)/$(CURDIR) -D__TIMER_NOLIBBASE__ + +%build_module mmake=kernel-sdcard \ + modname=sdcard modtype=device version=$(AROS_TARGET_PLATFORM) \ + files="sdcard_init sdcard_bus sdcard_device sdcard_ioops timer" \ + uselibs="oop" diff --git a/arch/arm-raspi/devs/sdcard/sdcard.conf b/arch/arm-raspi/devs/sdcard/sdcard.conf new file mode 100644 index 0000000000..8fbde095dd --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/sdcard.conf @@ -0,0 +1,42 @@ +##begin config +basename sdcard +version 41.0 +libbasetype struct SDCardBase +libbase SDCardBase +residentpri 4 +beginio_func BeginIO +abortio_func AbortIO +options noexpunge +##end config + +##begin cdefprivate +#include +##end cdefprivate + +##begin cdef +#include +#include +##end cdef + +##begin functionlist +ULONG GetRdskLba(struct IORequest *io) (A1) +ULONG GetBlkSize(struct IORequest *io) (A1) +##end functionlist + +##begin interface +##begin config +interfaceid hidd.sdcard.bus +interfacename Hidd_SDCardBus +methodstub HIDD_SDCardBus +methodbase HiddSDCardBusBase +attributebase HiddSDCardBusAttrBase +##end config + +##begin attributelist +IPTR IOBase # [..G] Address of registers bank +APTR IRQHandler # [.S.] Pointer to IRQ handler function +APTR IRQData # [.S.] Caller-supplied data to pass to IRQ handler +BOOL KeepEmpty # [I..] Tells if the empty bus should be kept +##end attributelist + +##end interface diff --git a/arch/arm-raspi/devs/sdcard/sdcard_bus.c b/arch/arm-raspi/devs/sdcard/sdcard_bus.c new file mode 100644 index 0000000000..a9d9aee625 --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/sdcard_bus.c @@ -0,0 +1,486 @@ +/* + Copyright © 2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "sdcard_intern.h" +#include "timer.h" + +#include LC_LIBDEFS_FILE + +UBYTE FNAME_SDCBUS(MMIOReadByte)(ULONG reg, struct sdcard_Bus *bus) +{ + ULONG val = *(volatile ULONG *)(((ULONG)bus->sdcb_IOBase + reg) & ~3); + + return (val >> ((reg & 3) << 3)) & 0xff; +} + +UWORD FNAME_SDCBUS(MMIOReadWord)(ULONG reg, struct sdcard_Bus *bus) +{ + ULONG val = *(volatile ULONG *)(((ULONG)bus->sdcb_IOBase + reg) & ~3); + + return (val >> (((reg >> 1) & 1) << 4)) & 0xffff; +} + +ULONG FNAME_SDCBUS(MMIOReadLong)(ULONG reg, struct sdcard_Bus *bus) +{ + return *(volatile ULONG *)(bus->sdcb_IOBase + reg); +} + +void FNAME_SDCBUS(ArasanWriteLong)(ULONG reg, ULONG val, struct sdcard_Bus *bus) +{ + /* Bug: two SDC clock cycle delay required between successive chipset writes */ + while (*((volatile ULONG *)(SYSTIMER_CLO)) < (bus->sdcb_LastWrite + 100)) + asm volatile("mov r0, r0\n"); + + *(volatile ULONG *)(bus->sdcb_IOBase + reg) = val; + bus->sdcb_LastWrite = *((volatile ULONG *)(SYSTIMER_CLO)); +} + +void FNAME_SDCBUS(MMIOWriteByte)(ULONG reg, UBYTE val, struct sdcard_Bus *bus) +{ + ULONG currval = *(volatile ULONG *)(((ULONG)bus->sdcb_IOBase + reg) & ~3); + ULONG shift = (reg & 3) * 8; + ULONG mask = 0xff << shift; + ULONG newval = (currval & ~mask) | (val << shift); + + FNAME_SDCBUS(ArasanWriteLong)(reg & ~3, newval, bus); +} + +void FNAME_SDCBUS(MMIOWriteWord)(ULONG reg, UWORD val, struct sdcard_Bus *bus) +{ + ULONG currval = *(volatile ULONG *)(((ULONG)bus->sdcb_IOBase + reg) & ~3); + ULONG shift = ((reg >> 1) & 1) * 16; + ULONG mask = 0xffff << shift; + ULONG newval = (currval & ~mask) | (val << shift); + + FNAME_SDCBUS(ArasanWriteLong)(reg & ~3, newval, bus); +} + +void FNAME_SDCBUS(MMIOWriteLong)(ULONG reg, ULONG val, struct sdcard_Bus *bus) +{ + FNAME_SDCBUS(ArasanWriteLong)(reg, val, bus); +} + +void FNAME_SDCBUS(SoftReset)(UBYTE mask, struct sdcard_Bus *bus) +{ + ULONG timeout = 10000, timeout_udelay; + + FNAME_SDCBUS(MMIOWriteByte)(SDHCI_RESET, mask, bus); + while (FNAME_SDCBUS(MMIOReadByte)(SDHCI_RESET, bus) & mask) { + if (timeout == 0) { + D(bug("[SDCard--] %s: Timeout\n", __PRETTY_FUNCTION__)); + break; + } + timeout_udelay = timeout - 1000; + for (; timeout > timeout_udelay; timeout --) asm volatile("mov r0, r0\n"); + } +} + +ULONG FNAME_SDCBUS(SendCmd)(struct TagItem *CmdTags, struct sdcard_Bus *bus) +{ + struct TagItem *Response = NULL; + + UWORD sdCommand = (UWORD)GetTagData(SDCARD_TAG_CMD, 0, CmdTags); + ULONG sdArg = GetTagData(SDCARD_TAG_ARG, 0, CmdTags); + ULONG sdResponseType = GetTagData(SDCARD_TAG_RSPTYPE, MMC_RSP_NONE, CmdTags); + ULONG sdData, sdDataLen = 0, sdDataFlags; + + UWORD sdcTransMode = 0, sdCommandFlags; + ULONG sdStatus = 0, sdCommandMask = SDHCI_PS_CMD_INHIBIT; + ULONG timeout = 10000, timeout_udelay; + ULONG ret = 0; + + if (sdResponseType != MMC_RSP_NONE) + { + Response = FindTagItem(SDCARD_TAG_RSP, CmdTags); + } + + if ((sdData = GetTagData(SDCARD_TAG_DATA, 0, CmdTags)) != 0) + { + sdDataLen = GetTagData(SDCARD_TAG_DATALEN, 0, CmdTags); + sdDataFlags = GetTagData(SDCARD_TAG_DATAFLAGS, 0, CmdTags); + if (!(sdDataLen)) + sdData = 0; + }; + + /* Dont wait for DATA inihibit for stop commands */ + if (sdCommand != MMC_CMD_STOP_TRANSMISSION) + sdCommandMask |= SDHCI_PS_DATA_INHIBIT; + + while (FNAME_SDCBUS(MMIOReadLong)(SDHCI_PRESENT_STATE, bus) & sdCommandMask) { + if (timeout == 0) { + D(bug("[SDCard--] %s: Controller failed to release inhibited bit(s).\n", __PRETTY_FUNCTION__)); + return -1; + } + timeout_udelay = timeout - 1000; + for (; timeout > timeout_udelay; timeout--) + asm volatile("mov r0, r0\n"); + } + + sdCommandMask = SDHCI_INT_RESPONSE; + if (!(sdResponseType & MMC_RSP_PRESENT)) + sdCommandFlags = SDHCI_CMD_RESP_NONE; + else if (sdResponseType & MMC_RSP_136) + sdCommandFlags = SDHCI_CMD_RESP_LONG; + else if (sdResponseType & MMC_RSP_BUSY) { + sdCommandFlags = SDHCI_CMD_RESP_SHORT_BUSY; + sdCommandMask |= SDHCI_INT_DATA_END; + } else + sdCommandFlags = SDHCI_CMD_RESP_SHORT; + + if (sdResponseType & MMC_RSP_CRC) + sdCommandFlags |= SDHCI_CMD_CRC; + if (sdResponseType & MMC_RSP_OPCODE) + sdCommandFlags |= SDHCI_CMD_INDEX; + if (sdData) + sdCommandFlags |= SDHCI_CMD_DATA; + + if (sdData != 0) { + sdcTransMode = SDHCI_TRANSMOD_BLK_CNT_EN; + D(bug("[SDCard--] %s: Configuring Data Transfer\n", __PRETTY_FUNCTION__)); + + *(volatile ULONG *)GPCLR0 = 1<<16; // Turn Activity LED ON + + FNAME_SDCBUS(MMIOWriteByte)(SDHCI_TIMEOUT_CONTROL, 0xe, bus); + + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_BLOCK_SIZE, 1 << bus->sdcb_SectorShift, bus); + if ((sdDataLen >> bus->sdcb_SectorShift) > 1) + { + sdcTransMode |= SDHCI_TRANSMOD_MULTI; + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_BLOCK_COUNT, sdDataLen >> bus->sdcb_SectorShift, bus); + } + else + { + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_BLOCK_COUNT, 1, bus); + } + + if (sdDataFlags == MMC_DATA_READ) + sdcTransMode |= SDHCI_TRANSMOD_READ; + + D(bug("[SDCard--] %s: Mode %08x, BlockSize %d, Count %d\n", __PRETTY_FUNCTION__, sdcTransMode, 1 << bus->sdcb_SectorShift, sdDataLen >> bus->sdcb_SectorShift)); + } + + FNAME_SDCBUS(MMIOWriteLong)(SDHCI_ARGUMENT, sdArg, bus); + if (sdcTransMode) + FNAME_SDCBUS(MMIOWriteLong)(SDHCI_TRANSFER_MODE, (sdcTransMode << 16) | SDHCI_MAKE_CMD(sdCommand, sdCommandFlags), bus); + else + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_COMMAND, SDHCI_MAKE_CMD(sdCommand, sdCommandFlags), bus); + + timeout = 10000; + do { + sdStatus = FNAME_SDCBUS(MMIOReadLong)(SDHCI_INT_STATUS, bus); + if (sdStatus & SDHCI_INT_ERROR) + break; + if (--timeout == 0) + break; + } while ((sdStatus & sdCommandMask) != sdCommandMask); + + if (timeout != 0) { + if ((sdStatus & (sdCommandMask|SDHCI_INT_ERROR)) == sdCommandMask) { + if (sdStatus & SDHCI_INT_ERROR) + { + D(bug("[SDCard--] %s: Error?", __PRETTY_FUNCTION__)); + } + + if (Response) + { + D(bug("[SDCard--] %s: Reading Response ", __PRETTY_FUNCTION__)); + if (sdResponseType & MMC_RSP_136) + { + D(bug("[136bit]\n")); + if (Response->ti_Data) + { + ULONG i; + for (i = 0; i < 4; i ++) + { + ((ULONG *)Response->ti_Data)[i] = FNAME_SDCBUS(MMIOReadLong)(SDHCI_RESPONSE + (3 - i) * 4, bus) << 8; + if (i != 3) + ((ULONG *)Response->ti_Data)[i] |= FNAME_SDCBUS(MMIOReadByte)(SDHCI_RESPONSE + (3 - i) * 4 - 1, bus); + } + } + } + else + { + D(bug("\n")); + Response->ti_Data = FNAME_SDCBUS(MMIOReadLong)(SDHCI_RESPONSE, bus); + } + } + FNAME_SDCBUS(MMIOWriteLong)(SDHCI_INT_STATUS, sdCommandMask, bus); + } + else + { + D(bug("[SDCard--] %s: Failed? [status = %08x]\n", __PRETTY_FUNCTION__, sdStatus)); + ret = -1; + } + + if (!ret && sdData) + { + D(bug("[SDCard--] %s: Transfering Data..\n", __PRETTY_FUNCTION__)); + timeout = 1000000; + sdCommand = SDHCI_INT_SPACE_AVAIL | SDHCI_INT_DATA_AVAIL; + sdCommandMask = SDHCI_PS_DATA_AVAILABLE | SDHCI_PS_SPACE_AVAILABLE; + do { + sdStatus = FNAME_SDCBUS(MMIOReadLong)(SDHCI_INT_STATUS, bus); + if (sdStatus & SDHCI_INT_ERROR) { + D(bug("[SDCard--] %s: Error [status 0x%X]!\n", __PRETTY_FUNCTION__, sdStatus)); + ret = -1; + break; + } + if (sdStatus & sdCommand) { + if (!(FNAME_SDCBUS(MMIOReadLong)(SDHCI_PRESENT_STATE, bus) & sdCommandMask)) + continue; + FNAME_SDCBUS(MMIOWriteLong)(SDHCI_INT_STATUS, sdCommand, bus); +#warning "TODO: Transfer bytes ;)" + } + if (timeout-- <= 0) + { + D(bug("[SDCard--] %s: Timeout!\n", __PRETTY_FUNCTION__)); + ret = -1; + break; + } + } while (!(sdStatus & SDHCI_INT_DATA_END)); + } + } + else + { + D(bug("[SDCard--] %s: Error - command timed out\n", __PRETTY_FUNCTION__)); + ret = -1; + } + timeout = 1000; + timeout_udelay = 0; + for (; timeout > timeout_udelay; timeout --) asm volatile("mov r0, r0\n"); + + *(volatile ULONG *)GPSET0 = (1 << 16); // Turn Activity LED OFF + + sdStatus = FNAME_SDCBUS(MMIOReadLong)(SDHCI_INT_STATUS, bus); + FNAME_SDCBUS(MMIOWriteLong)(SDHCI_INT_STATUS, SDHCI_INT_ALL_MASK, bus); + if (!ret) { + return 0; + } + + D(bug("[SDCard--] %s: Reseting SDHCI CMD/DATA\n", __PRETTY_FUNCTION__)); + + FNAME_SDCBUS(SoftReset)(SDHCI_RESET_CMD, bus); + FNAME_SDCBUS(SoftReset)(SDHCI_RESET_DATA, bus); + if (sdStatus & SDHCI_INT_TIMEOUT) + return -1; + else + return -1; +} + +ULONG FNAME_SDCBUS(Rsp136Unpack)(ULONG *buf, ULONG offset, const ULONG len) +{ + const ULONG mask = ((len < 32) ? (1 << len) : 0) - 1; + const ULONG shift = (offset) & 0x1F; + ULONG retval; + + retval = buf[3 - (offset >> 5)] >> shift; + if (len + shift > 32) + retval |= buf[3 - (offset >> 5) - 1] << ((32 - shift) % 32); + + return (retval & mask); +} + + +int FNAME_SDCBUS(SDUnitSwitch)(BOOL test, int group, UBYTE value, APTR buf, struct sdcard_Unit *sdcUnit) +{ + struct TagItem sdcSwitchTags[] = + { + {SDCARD_TAG_CMD, SD_CMD_SWITCH_FUNC}, + {SDCARD_TAG_ARG, 0}, + {SDCARD_TAG_RSPTYPE, MMC_RSP_R1}, + {SDCARD_TAG_RSP, 0}, + {SDCARD_TAG_DATA, buf}, + {SDCARD_TAG_DATALEN, 64}, + {SDCARD_TAG_DATAFLAGS, MMC_DATA_READ}, + {TAG_DONE, 0} + }; + + D(bug("[SDCard%02ld] %s()\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + sdcSwitchTags[1].ti_Data = ((test) ? 0 : (1 << 31)) | 0xffffff; + sdcSwitchTags[1].ti_Data &= ~(0xf << (group * 4)); + sdcSwitchTags[1].ti_Data |= value << (group * 4); + + return FNAME_SDCBUS(SendCmd)(sdcSwitchTags, sdcUnit->sdcu_Bus); +} + + +int FNAME_SDCBUS(SDUnitChangeFrequency)(struct sdcard_Unit *sdcUnit) +{ + unsigned int timeout; + struct TagItem sdcChFreqTags[] = + { + {SDCARD_TAG_CMD, 0}, + {SDCARD_TAG_ARG, 0}, + {SDCARD_TAG_RSPTYPE, 0}, + {SDCARD_TAG_RSP, 0}, + {TAG_DONE, 0}, /* SDCARD_TAG_DATA */ + {SDCARD_TAG_DATALEN, 0}, + {SDCARD_TAG_DATAFLAGS, MMC_DATA_READ}, + {TAG_DONE, 0} + }; + + /* Read the SCR to find out if higher speeds are supported ..*/ + + D(bug("[SDCard%02ld] %s: Attempt to send App Command ... \n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + sdcChFreqTags[0].ti_Data = MMC_CMD_APP_CMD; + sdcChFreqTags[1].ti_Data = sdcUnit->sdcu_CardRCA << 16; + sdcChFreqTags[2].ti_Data = MMC_RSP_R1; + if (FNAME_SDCBUS(SendCmd)(sdcChFreqTags, sdcUnit->sdcu_Bus) != -1) + { + ULONG sdcardRespBuf[2] = {0, 0}; + + sdcChFreqTags[0].ti_Data = SD_CMD_APP_SEND_SCR; + sdcChFreqTags[1].ti_Data = 0; + sdcChFreqTags[2].ti_Data = MMC_RSP_R1; + + timeout = 3; + D(bug("[SDCard%02ld] %s: Attempt to Query SCR Register ... \n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + do + { + sdcChFreqTags[4].ti_Tag = SDCARD_TAG_DATA; + sdcChFreqTags[4].ti_Data = sdcardRespBuf; + sdcChFreqTags[5].ti_Data = 8; + + if (FNAME_SDCBUS(SendCmd)(sdcChFreqTags, sdcUnit->sdcu_Bus) != -1) + break; + } while (timeout-- > 0); + + if (timeout > 0) + { + if (AROS_BE2LONG(sdcardRespBuf[0]) & SD_SCR_DATA4BIT) + sdcUnit->sdcu_Flags |= AF_4bitData; + + /* v1.0 SDCards don't support switching */ + if (((AROS_BE2LONG(sdcardRespBuf[0]) >> 24) & 0xf) < 1) + { + D(bug("[SDCard%02ld] %s: Card doesnt support Switching\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + return 0; + } + + timeout = 4; + while (timeout-- > 0) { + if (FNAME_SDCBUS(SDUnitSwitch)(TRUE, 0, 1, sdcardRespBuf, sdcUnit) != -1) + { + /* The high-speed function is busy. Try again */ + if (!(AROS_BE2LONG(sdcardRespBuf[7]) & SD_SCR_HIGHSPEED)) + break; + } + else + { + D(bug("[SDCard%02ld] %s: Switch failed\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + return -1; + } + } + + if (timeout > 0) + { + /* Is high-speed supported? */ + if (!(AROS_BE2LONG(sdcardRespBuf[3]) & SD_SCR_HIGHSPEED)) + { + D(bug("[SDCard%02ld] %s: Card doesnt support Highspeed mode\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + return 0; + } + + if (FNAME_SDCBUS(SDUnitSwitch)(FALSE, 0, 1, sdcardRespBuf, sdcUnit) != -1) + { + if ((AROS_BE2LONG(sdcardRespBuf[4]) & 0x0F000000) == 0x01000000) + sdcUnit->sdcu_Flags |= AF_HighSpeed; + } + } + } + else + { + D(bug("[SDCard%02ld] %s: Query Failed\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + } + } + else + { + D(bug("[SDCard%02ld] %s: App Command Failed\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + } +} + +void FNAME_SDCBUS(BusTask)(struct sdcard_Bus *bus) +{ + struct SDCardBase *SDCardBase = bus->sdcb_DeviceBase; + struct sdcard_Unit *unit; + struct IORequest *msg; + ULONG sdcReg; + ULONG sig; + + D(bug("[SDCard**] Task started (bus: %u)\n", bus->sdcb_BusNum)); + + bus->sdcb_Timer = sdcard_OpenTimer(SDCardBase); + + /* Get the signal used for sleeping */ + bus->sdcb_Task = FindTask(0); + bus->sdcb_TaskSig = AllocSignal(-1); + /* Failed to get it? Use SIGBREAKB_CTRL_E instead */ + if (bus->sdcb_TaskSig < 0) + bus->sdcb_TaskSig = SIGBREAKB_CTRL_E; + + sig = 1L << bus->sdcb_MsgPort->mp_SigBit; + + sdcReg = FNAME_SDCBUS(MMIOReadLong)(SDHCI_PRESENT_STATE, bus); + if (sdcReg & SDHCI_PS_CARD_PRESENT) + { + FNAME_SDC(RegisterVolume)(bus); + } + + /* Wait forever and process messages */ + for (;;) + { + Wait(sig); + + /* Even if you get new signal, do not process it until Unit is not active */ + if (!(bus->sdcb_BusFlags & UNITF_ACTIVE)) + { + bus->sdcb_BusFlags |= UNITF_ACTIVE; + + /* Empty the request queue */ + while ((msg = (struct IORequest *)GetMsg(bus->sdcb_MsgPort))) + { + /* And do IO's */ + if (FNAME_SDC(HandleIO)(msg)) + { + ReplyMsg((struct Message *)msg); + } + } + + bus->sdcb_BusFlags &= ~(UNITF_INTASK | UNITF_ACTIVE); + } + } +} diff --git a/arch/arm-raspi/devs/sdcard/sdcard_device.c b/arch/arm-raspi/devs/sdcard/sdcard_device.c new file mode 100644 index 0000000000..e30777f66e --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/sdcard_device.c @@ -0,0 +1,698 @@ +/* + Copyright © 2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 +#include + +#include +#include +#include +#include +#include +#include +#include "timer.h" + +#include + +#include +#include + +#include "sdcard_intern.h" +#include LC_LIBDEFS_FILE + +//---------------------------IO Commands--------------------------------------- + +/* Invalid comand does nothing, complains only. */ +static void cmd_Invalid(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + D(bug("[SDCard%02ld] %s: %d\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__, io->io_Command)); + io->io_Error = IOERR_NOCMD; +} + +/* Don't need to reset the drive? */ +static void cmd_Reset(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + IOStdReq(io)->io_Actual = 0; +} + +/* CMD_READ implementation */ +static void cmd_Read32(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)IOStdReq(io)->io_Unit; + + if (!(unit->sdcu_Flags & AF_MediaPresent)) + { + D(bug("[SDCard%02ld] %s: Error: No Media present\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + io->io_Error = TDERR_DiskChanged; + return; + } + + ULONG block = IOStdReq(io)->io_Offset; + ULONG count = IOStdReq(io)->io_Length; + + D(bug("[SDCard%02ld] cmd_Read32(%08x, %08x)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, block, count)); + + ULONG mask = (1 << unit->sdcu_Bus->sdcb_SectorShift) - 1; + + /* + During this IO call it should be sure that both offset and + length are already aligned properly to sector boundaries. + */ + if ((block & mask) | (count & mask)) + { + D(bug("[SDCard%02ld] cmd_Read32: offset or length not sector-aligned.\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum)); + cmd_Invalid(io, LIBBASE); + } + else + { + block >>= unit->sdcu_Bus->sdcb_SectorShift; + count >>= unit->sdcu_Bus->sdcb_SectorShift; + ULONG cnt = 0; + + if (((block + count) > unit->sdcu_Capacity)) + { + bug("[SDCard%02ld] cmd_Read32: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, block, count, unit->sdcu_Capacity); + io->io_Error = IOERR_BADADDRESS; + return; + } + + /* Call the Unit's access funtion */ + io->io_Error = unit->sdcu_Read32(unit, block, count, + IOStdReq(io)->io_Data, &cnt); + + IOStdReq(io)->io_Actual = cnt; + } +} + +/* + NSCMD_TD_READ64, TD_READ64 implementation. Basically the same, just packs + the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32) +*/ +static void cmd_Read64(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)IOStdReq(io)->io_Unit; + + if (!(unit->sdcu_Flags & AF_MediaPresent)) + { + D(bug("[SDCard%02ld] %s: Error: No Media present\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + io->io_Error = TDERR_DiskChanged; + return; + } + + UQUAD block = IOStdReq(io)->io_Offset | (UQUAD)(IOStdReq(io)->io_Actual) << 32; + ULONG count = IOStdReq(io)->io_Length; + + D(bug("[SDCard%02ld] cmd_Read64(%08x-%08x, %08x)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, IOStdReq(io)->io_Actual, IOStdReq(io)->io_Offset, count)); + + ULONG mask = (1 << unit->sdcu_Bus->sdcb_SectorShift) - 1; + + if ((block & (UQUAD)mask) | (count & mask) | (count == 0)) + { + D(bug("[SDCard%02ld] cmd_Read64: offset or length not sector-aligned.\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum)); + cmd_Invalid(io, LIBBASE); + } + else + { + block >>= unit->sdcu_Bus->sdcb_SectorShift; + count >>= unit->sdcu_Bus->sdcb_SectorShift; + ULONG cnt = 0; + + /* + If the sum of sector offset and the sector count doesn't overflow + the 28-bit LBA address, use 32-bit access for speed and simplicity. + Otherwise do the 48-bit LBA addressing. + */ + if (((block + count) > unit->sdcu_Capacity)) + { + bug("[SDCard%02ld] cmd_Read64: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, block, count, unit->sdcu_Capacity); + io->io_Error = IOERR_BADADDRESS; + return; + } + io->io_Error = unit->sdcu_Read32(unit, (ULONG)(block & 0x0fffffff), count, IOStdReq(io)->io_Data, &cnt); + + IOStdReq(io)->io_Actual = cnt; + } +} + +/* CMD_WRITE implementation */ +static void cmd_Write32(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)IOStdReq(io)->io_Unit; + + if (!(unit->sdcu_Flags & AF_MediaPresent)) + { + D(bug("[SDCard%02ld] %s: Error: No Media present\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + io->io_Error = TDERR_DiskChanged; + return; + } + + ULONG block = IOStdReq(io)->io_Offset; + ULONG count = IOStdReq(io)->io_Length; + + D(bug("[SDCard%02ld] cmd_Write32(%08x, %08x)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, block, count)); + + ULONG mask = (1 << unit->sdcu_Bus->sdcb_SectorShift) - 1; + + /* + During this IO call it should be sure that both offset and + length are already aligned properly to sector boundaries. + */ + if ((block & mask) | (count & mask)) + { + D(bug("[SDCard%02ld] cmd_Write32: offset or length not sector-aligned.\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum)); + cmd_Invalid(io, LIBBASE); + } + else + { + block >>= unit->sdcu_Bus->sdcb_SectorShift; + count >>= unit->sdcu_Bus->sdcb_SectorShift; + ULONG cnt = 0; + + if (((block + count) > unit->sdcu_Capacity)) + { + bug("[SDCard%02ld] cmd_Write32: Requested block (%lx;%ld) outside disk range (%lx)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, + block, count, unit->sdcu_Capacity); + io->io_Error = IOERR_BADADDRESS; + return; + } + + /* Call the Unit's access funtion */ + io->io_Error = unit->sdcu_Write32(unit, block, count, + IOStdReq(io)->io_Data, &cnt); + + IOStdReq(io)->io_Actual = cnt; + } +} + +/* + NSCMD_TD_WRITE64, TD_WRITE64 implementation. Basically the same, just packs + the 64 bit offset in both io_Offset (31:0) and io_Actual (63:32) +*/ +static void cmd_Write64(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)IOStdReq(io)->io_Unit; + + if (!(unit->sdcu_Flags & AF_MediaPresent)) + { + D(bug("[SDCard%02ld] %s: Error: No Media present\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + io->io_Error = TDERR_DiskChanged; + return; + } + + UQUAD block = IOStdReq(io)->io_Offset | (UQUAD)(IOStdReq(io)->io_Actual) << 32; + ULONG count = IOStdReq(io)->io_Length; + + D(bug("[SDCard%02ld] cmd_Write64(%08x-%08x, %08x)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, IOStdReq(io)->io_Actual, IOStdReq(io)->io_Offset, count)); + + ULONG mask = (1 << unit->sdcu_Bus->sdcb_SectorShift) - 1; + + if ((block & mask) | (count & mask) | (count==0)) + { + D(bug("[SDCard%02ld] cmd_Write64: offset or length not sector-aligned.\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum)); + cmd_Invalid(io, LIBBASE); + } + else + { + block >>= unit->sdcu_Bus->sdcb_SectorShift; + count >>= unit->sdcu_Bus->sdcb_SectorShift; + ULONG cnt = 0; + + /* + If the sum of sector offset and the sector count doesn't overflow + the 28-bit LBA address, use 32-bit access for speed and simplicity. + Otherwise do the 48-bit LBA addressing. + */ + if (((block + count) > unit->sdcu_Capacity)) + { + bug("[SDCard%02ld] cmd_Write64: Requested block (%lx:%08lx;%ld) outside disk " + "range (%lx:%08lx)\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, + block>>32, block&0xfffffffful, + count, unit->sdcu_Capacity>>32, + unit->sdcu_Capacity & 0xfffffffful); + io->io_Error = IOERR_BADADDRESS; + return; + } + + io->io_Error = unit->sdcu_Write64(unit, block, count, + IOStdReq(io)->io_Data, &cnt); + + IOStdReq(io)->io_Actual = cnt; + } +} + + +/* use CMD_FLUSH to force all IO waiting commands to abort */ +static void cmd_Flush(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct IORequest *msg; + D(bug("[SDCard%02ld] cmd_Flush()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum)); + + Forbid(); + +// while((msg = (struct IORequest *)GetMsg((struct MsgPort *)bus->sdb_MsgPort))) +// { +// msg->io_Error = IOERR_ABORTED; +// ReplyMsg((struct Message *)msg); +// } + + Permit(); +} + +/* + Internal command used to check whether the media in drive has been changed + since last call. If so, the handlers given by user are called. +*/ +static void cmd_TestChanged(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + struct IORequest *msg; + + D(bug("[SDCard%02ld] cmd_TestChanged()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum)); + + if (unit->sdcu_Flags & AF_MediaChanged) + { + unit->sdcu_ChangeNum++; + + Forbid(); + + /* old-fashioned RemoveInt call first */ + if (unit->sdcu_RemoveInt) + Cause(unit->sdcu_RemoveInt); + + /* And now the whole list of possible calls */ + ForeachNode(&unit->sdcu_SoftList, msg) + { + Cause((struct Interrupt *)IOStdReq(msg)->io_Data); + } + + unit->sdcu_Flags &= ~AF_MediaChanged; + + Permit(); + } +} + +static void cmd_Update(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + /* Do nothing now. In near future there should be drive cache flush though */ + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); +} + +static void cmd_Remove(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + if (unit->sdcu_RemoveInt) + io->io_Error = TDERR_DriveInUse; + else + unit->sdcu_RemoveInt = IOStdReq(io)->io_Data; +} + +static void cmd_ChangeNum(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + IOStdReq(io)->io_Actual = ((struct sdcard_Unit *)io->io_Unit)->sdcu_ChangeNum; +} + +static void cmd_ChangeState(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + if (unit->sdcu_Flags & AF_MediaPresent) + IOStdReq(io)->io_Actual = 0; + else + IOStdReq(io)->io_Actual = 1; + + D(bug("[SDCard%02ld] cmd_ChangeState: Media %s\n", unit->sdcu_UnitNum, IOStdReq(io)->io_Actual ? "ABSENT" : "PRESENT")); +} + +static void cmd_ProtStatus(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + if (unit->sdcu_DevType) + IOStdReq(io)->io_Actual = -1; + else + IOStdReq(io)->io_Actual = 0; + +} + +static void cmd_GetNumTracks(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + IOStdReq(io)->io_Actual = ((struct sdcard_Unit *)io->io_Unit)->sdcu_Cylinders; +} + +static void cmd_AddChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + Forbid(); + AddHead(&unit->sdcu_SoftList, (struct Node *)io); + Permit(); + + io->io_Flags &= ~IOF_QUICK; + unit->sdcu_Unit.unit_flags &= ~UNITF_ACTIVE; +} + +static void cmd_RemChangeInt(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + Forbid(); + Remove((struct Node *)io); + Permit(); +} + +static void cmd_Eject(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + IOStdReq(io)->io_Error = unit->sdcu_Eject(unit); + cmd_TestChanged(io, LIBBASE); +} + +static void cmd_GetGeometry(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + if (IOStdReq(io)->io_Length == sizeof(struct DriveGeometry)) + { + struct DriveGeometry *dg = (struct DriveGeometry *)IOStdReq(io)->io_Data; + + dg->dg_SectorSize = 1 << unit->sdcu_Bus->sdcb_SectorShift; + + if ((unit->sdcu_Capacity >> 32) != 0) + dg->dg_TotalSectors = 0xffffffff; + else + dg->dg_TotalSectors = unit->sdcu_Capacity; + + dg->dg_Cylinders = unit->sdcu_Cylinders; + dg->dg_CylSectors = unit->sdcu_Sectors * unit->sdcu_Heads; + dg->dg_Heads = unit->sdcu_Heads; + dg->dg_TrackSectors = unit->sdcu_Sectors; + dg->dg_BufMemType = MEMF_PUBLIC; + dg->dg_DeviceType = DG_DIRECT_ACCESS; + dg->dg_Flags = DGF_REMOVABLE; + dg->dg_Reserved = 0; + + IOStdReq(io)->io_Actual = sizeof(struct DriveGeometry); + } + else io->io_Error = TDERR_NotSpecified; +} + +static void cmd_DirectSCSI(struct IORequest *io, LIBBASETYPEPTR LIBBASE) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + IOStdReq(io)->io_Actual = sizeof(struct SCSICmd); + io->io_Error = IOERR_BADADDRESS; +} + +//----------------------------------------------------------------------------- + +/* + command translation tables - used to call proper IO functions. +*/ + +#define N_TD_READ64 0 +#define N_TD_WRITE64 1 +#define N_TD_SEEK64 2 +#define N_TD_FORMAT64 3 + +typedef void (*mapfunc)(struct IORequest *, LIBBASETYPEPTR); + +static mapfunc const map64[]= { + [N_TD_READ64] = cmd_Read64, + [N_TD_WRITE64] = cmd_Write64, + [N_TD_SEEK64] = cmd_Reset, + [N_TD_FORMAT64] = cmd_Write64 +}; + +static mapfunc const map32[] = { + [CMD_INVALID] = cmd_Invalid, + [CMD_RESET] = cmd_Reset, + [CMD_READ] = cmd_Read32, + [CMD_WRITE] = cmd_Write32, + [CMD_UPDATE] = cmd_Update, + [CMD_CLEAR] = cmd_Reset, + [CMD_STOP] = cmd_Reset, + [CMD_START] = cmd_Reset, + [CMD_FLUSH] = cmd_Flush, + [TD_MOTOR] = cmd_Reset, + [TD_SEEK] = cmd_Reset, + [TD_FORMAT] = cmd_Write32, + [TD_REMOVE] = cmd_Remove, + [TD_CHANGENUM] = cmd_ChangeNum, + [TD_CHANGESTATE]= cmd_ChangeState, + [TD_PROTSTATUS] = cmd_ProtStatus, + [TD_RAWREAD] = cmd_Invalid, + [TD_RAWWRITE] = cmd_Invalid, + [TD_GETNUMTRACKS] = cmd_GetNumTracks, + [TD_ADDCHANGEINT] = cmd_AddChangeInt, + [TD_REMCHANGEINT] = cmd_RemChangeInt, + [TD_GETGEOMETRY]= cmd_GetGeometry, + [TD_EJECT] = cmd_Eject, + [TD_READ64] = cmd_Read64, + [TD_WRITE64] = cmd_Write64, + [TD_SEEK64] = cmd_Reset, + [TD_FORMAT64] = cmd_Write64, + [HD_SCSICMD] = cmd_DirectSCSI, + [HD_SCSICMD+1] = cmd_TestChanged, +}; + +static UWORD const NSDSupported[] = { + CMD_RESET, + CMD_READ, + CMD_WRITE, + CMD_UPDATE, + CMD_CLEAR, + CMD_STOP, + CMD_START, + CMD_FLUSH, + TD_MOTOR, + TD_SEEK, + TD_FORMAT, + TD_REMOVE, + TD_CHANGENUM, + TD_CHANGESTATE, + TD_PROTSTATUS, + TD_GETNUMTRACKS, + TD_ADDCHANGEINT, + TD_REMCHANGEINT, + TD_GETGEOMETRY, + TD_EJECT, + TD_READ64, + TD_WRITE64, + TD_SEEK64, + TD_FORMAT64, + HD_SCSICMD, + TD_GETDRIVETYPE, + NSCMD_DEVICEQUERY, + NSCMD_TD_READ64, + NSCMD_TD_WRITE64, + NSCMD_TD_SEEK64, + NSCMD_TD_FORMAT64, + 0 +}; + +/* + Do proper IO actions depending on the request. It's called from the bus + tasks and from BeginIO in case of immediate commands. +*/ +BOOL FNAME_SDC(HandleIO)(struct IORequest *io) +{ + BOOL retval = TRUE; + LIBBASETYPEPTR LIBBASE = ((struct sdcard_Unit*)io->io_Unit)->sdcu_Bus->sdcb_DeviceBase; + + io->io_Error = 0; + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + /* Handle few commands directly here */ + switch (io->io_Command) + { + /* + New Style Devices query. Introduce self as trackdisk and provide list of + commands supported + */ + case NSCMD_DEVICEQUERY: + { + struct NSDeviceQueryResult *nsdq = (struct NSDeviceQueryResult *)IOStdReq(io)->io_Data; + nsdq->DevQueryFormat = 0; + nsdq->SizeAvailable = sizeof(struct NSDeviceQueryResult); + nsdq->DeviceType = NSDEVTYPE_TRACKDISK; + nsdq->DeviceSubType = 0; + nsdq->SupportedCommands = (UWORD *)NSDSupported; + } + IOStdReq(io)->io_Actual = sizeof(struct NSDeviceQueryResult); + break; + + /* + New Style Devices report here the 'NSTY' - only if such value is + returned here, the NSCMD_DEVICEQUERY might be called. Otherwice it should + report error. + */ + case TD_GETDRIVETYPE: + IOStdReq(io)->io_Actual = DRIVE_NEWSTYLE; + break; + + case TD_ADDCHANGEINT: + retval = FALSE; + /* + Call all other commands using the command pointer tables for 32- and + 64-bit accesses. If requested function is defined call it, otherwise + make the function cmd_Invalid. + */ + default: + if (io->io_Command <= (HD_SCSICMD + 1)) + { + if (map32[io->io_Command]) + map32[io->io_Command](io, LIBBASE); + else + cmd_Invalid(io, LIBBASE); + } + else if (io->io_Command >= NSCMD_TD_READ64 && io->io_Command <= NSCMD_TD_FORMAT64) + { + if (map64[io->io_Command - NSCMD_TD_READ64]) + map64[io->io_Command - NSCMD_TD_READ64](io, LIBBASE); + else + cmd_Invalid(io, LIBBASE); + } + else cmd_Invalid(io, LIBBASE); + break; + } + return retval; +} + + +static const ULONG IMMEDIATE_COMMANDS = 0x803ff1e3; // 10000000001111111111000111100011 + +/* See whether the command can be done quick */ +BOOL isSlow(ULONG comm) +{ + BOOL slow = TRUE; /* Assume always slow command */ + + /* For commands with numbers <= 31 check the mask */ + if (comm <= 31) + { + if (IMMEDIATE_COMMANDS & (1 << comm)) + slow = FALSE; + } + else if (comm == NSCMD_TD_SEEK64) slow = FALSE; + + return slow; +} + +/* + Try to do IO commands. All commands which require talking with mci devices + will be handled slow, that is they will be passed to bus task which will + execute them as soon as hardware will be free. +*/ +AROS_LH1(void, BeginIO, + AROS_LHA(struct IORequest *, io, A1), + LIBBASETYPEPTR, LIBBASE, 5, sdcard) +{ + AROS_LIBFUNC_INIT + + struct sdcard_Unit *unit = (struct sdcard_Unit *)io->io_Unit; + + io->io_Message.mn_Node.ln_Type = NT_MESSAGE; + + /* Disable interrupts for a while to modify message flags */ + Disable(); + + D(bug("[SDCard%02ld] %s: Executing IO Command %lx\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__, io->io_Command)); + + /* + If the command is not-immediate, or presence of disc is still unknown, + let the bus task do the job. + */ + if (isSlow(io->io_Command)) + { + unit->sdcu_Unit.unit_flags |= UNITF_ACTIVE | UNITF_INTASK; + io->io_Flags &= ~IOF_QUICK; + Enable(); + + /* Put the message to the bus */ + PutMsg(unit->sdcu_Bus->sdcb_MsgPort, (struct Message *)io); + } + else + { + D(bug("[SDCard%02ld] %s: Fast command\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + /* Immediate command. Mark unit as active and do the command directly */ + unit->sdcu_Unit.unit_flags |= UNITF_ACTIVE; + Enable(); + if (FNAME_SDC(HandleIO)(io)) + { + unit->sdcu_Unit.unit_flags &= ~UNITF_ACTIVE; + if (!(io->io_Flags & IOF_QUICK)) + ReplyMsg((struct Message *)io); + } + else + unit->sdcu_Unit.unit_flags &= ~UNITF_ACTIVE; + } + + D(bug("[SDCard%02ld] %s: Done\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + AROS_LIBFUNC_EXIT +} + +AROS_LH1(LONG, AbortIO, + AROS_LHA(struct IORequest *, io, A1), + LIBBASETYPEPTR, LIBBASE, 6, sdcard) +{ + AROS_LIBFUNC_INIT + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + /* Cannot Abort IO */ + return 0; + + AROS_LIBFUNC_EXIT +} + +AROS_LH1(ULONG, GetRdskLba, + AROS_LHA(struct IORequest *, io, A1), + LIBBASETYPEPTR, LIBBASE, 7, sdcard) +{ + AROS_LIBFUNC_INIT + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; + + AROS_LIBFUNC_EXIT +} + +AROS_LH1(ULONG, GetBlkSize, + AROS_LHA(struct IORequest *, io, A1), + LIBBASETYPEPTR, LIBBASE, 8, sdcard) +{ + AROS_LIBFUNC_INIT + + D(bug("[SDCard%02ld] %s()\n", ((struct sdcard_Unit*)io->io_Unit)->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return Unit(io)->sdcu_Bus->sdcb_SectorShift; + + AROS_LIBFUNC_EXIT +} diff --git a/arch/arm-raspi/devs/sdcard/sdcard_init.c b/arch/arm-raspi/devs/sdcard/sdcard_init.c new file mode 100644 index 0000000000..01f48c9a85 --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/sdcard_init.c @@ -0,0 +1,611 @@ +/* + Copyright © 2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "sdcard_intern.h" +#include "timer.h" + +#include LC_LIBDEFS_FILE + +#define VCMB_PROPCHAN 8 +#define VCMBoxBase SDCardBase->sdcard_VCMBoxBase + +unsigned int VCMBoxMessage[8] __attribute__((used,aligned(16))); + +BOOL FNAME_SDC(RegisterVolume)(struct sdcard_Bus *bus) +{ + struct SDCardBase *SDCardBase = bus->sdcb_DeviceBase; + struct sdcard_Unit *sdcUnit = NULL; + unsigned int timeout = 1000000, timeout_udelay = 2000; + struct DeviceNode *devnode; + BOOL sdcHighCap = FALSE; + struct TagItem sdcRegTags[] = + { + {SDCARD_TAG_CMD, 0}, + {SDCARD_TAG_ARG, 0}, + {SDCARD_TAG_RSPTYPE, 0}, + {SDCARD_TAG_RSP, 0}, + {TAG_DONE, 0} + }; + + D(bug("[SDCard>>] %s()\n", __PRETTY_FUNCTION__)); + + if ((ExpansionBase = (struct ExpansionBase *)OpenLibrary("expansion.library", 40L)) != NULL) + { + IPTR pp[24]; + ULONG response136[4] = {0, 0, 0, 0}; + + D(bug("[SDCard>>] %s: Telling controller to idle...\n", __PRETTY_FUNCTION__)); + sdcRegTags[0].ti_Data = MMC_CMD_GO_IDLE_STATE; + sdcRegTags[1].ti_Data = 0; + sdcRegTags[2].ti_Data = MMC_RSP_NONE; + if (FNAME_SDCBUS(SendCmd)(sdcRegTags, bus) == -1) + { + D(bug("[SDCard>>] %s: Failed to go idle?\n", __PRETTY_FUNCTION__)); + CloseLibrary((struct Library *)ExpansionBase); + return FALSE; + } + + for (; timeout_udelay > 0; timeout_udelay --) asm volatile("mov r0, r0\n"); + + sdcRegTags[0].ti_Data = SD_CMD_SEND_IF_COND; + sdcRegTags[1].ti_Data = ((bus->sdcb_Power & 0xFF8000) != 0) << 8 | 0xAA; + sdcRegTags[2].ti_Data = MMC_RSP_R7; + D(bug("[SDCard>>] %s: Querying Interface conditions [%08x] ... ", __PRETTY_FUNCTION__, sdcRegTags[1].ti_Data)); + + if ((FNAME_SDCBUS(SendCmd)(sdcRegTags, bus)) != -1) + { + D(bug("response %08x\n", sdcRegTags[3].ti_Data)); + + do { + D(bug("[SDCard>>] %s: Attempt to send an App Command ... ", __PRETTY_FUNCTION__)); + sdcRegTags[0].ti_Data = MMC_CMD_APP_CMD; + sdcRegTags[1].ti_Data = 0; + sdcRegTags[2].ti_Data = MMC_RSP_R1; + + if (FNAME_SDCBUS(SendCmd)(sdcRegTags, bus) == -1) + { + D(bug("error (-1)\n")); + CloseLibrary((struct Library *)ExpansionBase); + return FALSE; + } + D(bug("response %08x\n", sdcRegTags[3].ti_Data)); + + sdcRegTags[0].ti_Data = SD_CMD_APP_SEND_OP_COND; + sdcRegTags[1].ti_Data = (bus->sdcb_Power & 0xFF8000) | OCR_HCS; + sdcRegTags[2].ti_Data = MMC_RSP_R3; + + D(bug("[SDCard>>] %s: Querying Operating conditions [%08x] ... ", __PRETTY_FUNCTION__, sdcRegTags[1].ti_Data)); + if (FNAME_SDCBUS(SendCmd)(sdcRegTags, bus) != -1) + { + D(bug("response %08x\n", sdcRegTags[3].ti_Data)); + timeout_udelay = timeout - 1000; + for (; timeout > timeout_udelay; timeout --) asm volatile("mov r0, r0\n"); + } + else + { + D(bug("error (-1)\n")); + CloseLibrary((struct Library *)ExpansionBase); + return FALSE; + } + } while ((!(sdcRegTags[3].ti_Data & OCR_BUSY)) && timeout--); + + if (timeout > 0) + { + D(bug("[SDCard>>] %s: Card OCR = %08x\n", __PRETTY_FUNCTION__, (sdcRegTags[3].ti_Data & 0xFFFF00))); + + if (sdcRegTags[3].ti_Data & OCR_HCS) + sdcHighCap = TRUE; + + D(bug("[SDCard>>] %s: Card is now operating in Identification Mode\n", __PRETTY_FUNCTION__)); + + /* Put the "card" into identify mode*/ + D(bug("[SDCard>>] %s: Querying Card Identification Data ...\n", __PRETTY_FUNCTION__)); + sdcRegTags[0].ti_Data = MMC_CMD_ALL_SEND_CID; + sdcRegTags[1].ti_Data = 0; + sdcRegTags[2].ti_Data = MMC_RSP_R2; + sdcRegTags[3].ti_Data = response136; + if (FNAME_SDCBUS(SendCmd)(sdcRegTags, bus) != -1) + { + if (sdcRegTags[3].ti_Data) + { + D(bug("[SDCard>>] %s: %08x%08x%08x%08x\n", __PRETTY_FUNCTION__, response136[0], response136[1], response136[2], response136[3])); + D(bug("[SDCard>>] %s: Card Identification Data (CID) Register\n", __PRETTY_FUNCTION__)); + D(bug("[SDCard>>] %s: ======================================\n", __PRETTY_FUNCTION__)); + D(bug("[SDCard>>] %s: Manuafacturer ID (MID) : %06x\n", __PRETTY_FUNCTION__, FNAME_SDCBUS(Rsp136Unpack)(response136, 120, 8))); + D(bug("[SDCard>>] %s: Product Name (PNM) : %c%c%c%c%c\n", __PRETTY_FUNCTION__, FNAME_SDCBUS(Rsp136Unpack)(response136, 96, 8), FNAME_SDCBUS(Rsp136Unpack)(response136, 88, 8), FNAME_SDCBUS(Rsp136Unpack)(response136, 80, 8), FNAME_SDCBUS(Rsp136Unpack)(response136, 72, 8), FNAME_SDCBUS(Rsp136Unpack)(response136, 64, 8))); + D(bug("[SDCard>>] %s: Product Revision (PRV) : %d.%d\n", __PRETTY_FUNCTION__, FNAME_SDCBUS(Rsp136Unpack)(response136, 60, 4), FNAME_SDCBUS(Rsp136Unpack)(response136, 56, 4))); + D(bug("[SDCard>>] %s: Serial number (PSN) : %08x\n", __PRETTY_FUNCTION__, FNAME_SDCBUS(Rsp136Unpack)(response136, 24, 32))); + D(bug("[SDCard>>] %s: Manufacturing Date Code (MDT) : %d/%d\n", __PRETTY_FUNCTION__, FNAME_SDCBUS(Rsp136Unpack)(response136, 8, 4), FNAME_SDCBUS(Rsp136Unpack)(response136, 12, 8))); + D(bug("[SDCard>>] %s: CRC7 checksum (CRC7) : %x\n", __PRETTY_FUNCTION__, FNAME_SDCBUS(Rsp136Unpack)(response136, 1, 7))); + D(bug("[SDCard>>] %s: Reserved : %x\n", __PRETTY_FUNCTION__, FNAME_SDCBUS(Rsp136Unpack)(response136, 0, 1))); + } + + D(bug("[SDCard>>] %s: Querying Card Relative Address... ", __PRETTY_FUNCTION__)); + sdcRegTags[0].ti_Data = SD_CMD_SEND_RELATIVE_ADDR; + sdcRegTags[1].ti_Data = 0; + sdcRegTags[2].ti_Data = MMC_RSP_R6; + sdcRegTags[3].ti_Data = NULL; + if (FNAME_SDCBUS(SendCmd)(sdcRegTags, bus) != -1) + { + if ((sdcUnit = AllocVecPooled(SDCardBase->sdcard_MemPool, sizeof(struct sdcard_Unit))) != NULL) + { + sdcUnit->sdcu_Bus = bus; + sdcUnit->sdcu_UnitNum = bus->sdcb_UnitCnt++; + bus->sdcb_Units[sdcUnit->sdcu_UnitNum] = sdcUnit; + sdcUnit->sdcu_CardRCA = (sdcRegTags[3].ti_Data >> 16) & 0xFFFF; + D(bug("[RCA %d]\n", sdcUnit->sdcu_CardRCA)); + + sdcRegTags[0].ti_Data = MMC_CMD_SEND_CSD; + sdcRegTags[1].ti_Data = sdcUnit->sdcu_CardRCA << 16; + sdcRegTags[2].ti_Data = MMC_RSP_R2; + sdcRegTags[3].ti_Data = response136; + D(bug("[SDCard%02ld] %s: Querying Card Specific Data [%08x] ...\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, sdcRegTags[1].ti_Data)); + if (FNAME_SDCBUS(SendCmd)(sdcRegTags, bus) != -1) + { + if (sdcRegTags[3].ti_Data) + { + int __csdstruct = FNAME_SDCBUS(Rsp136Unpack)(response136, 126, 2); + D(bug("[SDCard%02ld] %s: %08x%08x%08x%08x\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, response136[0], response136[1], response136[2], response136[3])); + D(bug("[SDCard%02ld] %s: Card Specific Data (CSD) Register\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + D(bug("[SDCard%02ld] %s: =================================\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + D(bug("[SDCard%02ld] %s: CSD_STRUCTURE : %x ", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, __csdstruct)); + + sdcUnit->sdcu_Read32 = FNAME_SDCIO(ReadSector32); + sdcUnit->sdcu_Write32 = FNAME_SDCIO(WriteSector32); + sdcUnit->sdcu_Flags = AF_MediaPresent; + if (sdcHighCap) + sdcUnit->sdcu_Flags |= AF_HighCapacity; + + switch (__csdstruct) + { + case 0: + { + D(bug("[SDSC Card]\n")); + pp[DE_SIZEBLOCK + 4] = 2 << (FNAME_SDCBUS(Rsp136Unpack)(response136, 80, 4) - 1); + pp[DE_SECSPERBLOCK + 4] = pp[DE_SIZEBLOCK + 4] >> 9; + pp[DE_HIGHCYL + 4] = ((1 + FNAME_SDCBUS(Rsp136Unpack)(response136, 62, 12)) << (FNAME_SDCBUS(Rsp136Unpack)(response136, 47, 3) + 2)); + break; + } + case 1: + { + D(bug("[SDHC/XC Card]\n")); + + pp[DE_SECSPERBLOCK + 4] = 2; + pp[DE_SIZEBLOCK + 4] = 2 << (10 - 1); + pp[DE_HIGHCYL + 4] = ((1 + FNAME_SDCBUS(Rsp136Unpack)(response136, 48, 22)) * (2 << (9 - 1))); + + sdcUnit->sdcu_Flags |= AF_MMC; + + sdcUnit->sdcu_Read64 = FNAME_SDCIO(ReadSector64); + sdcUnit->sdcu_Write64 = FNAME_SDCIO(WriteSector64); + break; + } + default: + D(bug("[SDCard%02ld] %s: Unsupported Card\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + CloseLibrary((struct Library *)ExpansionBase); + return FALSE; + } + + sdcUnit->sdcu_Cylinders = pp[DE_HIGHCYL + 4]; + sdcUnit->sdcu_Heads = 1; + sdcUnit->sdcu_Sectors = pp[DE_SECSPERBLOCK + 4]; + sdcUnit->sdcu_Capacity = sdcUnit->sdcu_Cylinders * sdcUnit->sdcu_Heads * sdcUnit->sdcu_Sectors; + + sdcUnit->sdcu_Eject = FNAME_SDCIO(Eject); + + D(bug("[SDCard%02ld] %s: READ_BL_LEN : %dbytes\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, pp[DE_SIZEBLOCK + 4] / sdcUnit->sdcu_Sectors)); + D(bug("[SDCard%02ld] %s: C_SIZE : %d\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, sdcUnit->sdcu_Cylinders)); + + pp[0] = (IPTR)"MMC0"; + pp[1] = (IPTR)MOD_NAME_STRING; + pp[2] = 0; + pp[DE_TABLESIZE + 4] = DE_BOOTBLOCKS; + pp[DE_NUMHEADS + 4] = sdcUnit->sdcu_Heads; + pp[DE_BLKSPERTRACK + 4] = 1; + pp[DE_RESERVEDBLKS + 4] = 2; + pp[DE_LOWCYL + 4] = 0; + pp[DE_NUMBUFFERS + 4] = 10; + pp[DE_BUFMEMTYPE + 4] = MEMF_PUBLIC | MEMF_31BIT; + pp[DE_MAXTRANSFER + 4] = 0x00200000; + pp[DE_MASK + 4] = 0x7FFFFFFE; + pp[DE_BOOTPRI + 4] = 0; + pp[DE_DOSTYPE + 4] = AROS_MAKE_ID('D','O','S','\001'); + pp[DE_CONTROL + 4] = 0; + pp[DE_BOOTBLOCKS + 4] = 2; + + devnode = MakeDosNode(pp); + + if (devnode) + { + D(bug("[SDCard%02ld] %s: %b: [%dMB Capacity]\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, devnode->dn_Name, sdcUnit->sdcu_Capacity >> 11)); + D(bug("[SDCard%02ld] %s: StartCyl:%d, EndCyl:%d ..\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, + pp[DE_LOWCYL + 4], pp[DE_HIGHCYL + 4])); + D(bug("[SDCard%02ld] %s: BlockSize:%d, SectorsPerBlock:%d ..\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, + pp[DE_SIZEBLOCK + 4], sdcUnit->sdcu_Sectors)); + + if (sdcUnit->sdcu_Flags & AF_MMC) + { + } + else + { + FNAME_SDCBUS(SDUnitChangeFrequency)(sdcUnit); + } + + if (!(sdcUnit->sdcu_Flags & AF_HighCapacity)) + { + sdcRegTags[0].ti_Data = MMC_CMD_SET_BLOCKLEN; + sdcRegTags[1].ti_Data = 1 << sdcUnit->sdcu_Bus->sdcb_SectorShift; + sdcRegTags[2].ti_Data = MMC_RSP_R1; + sdcRegTags[3].ti_Data = 0; + if (FNAME_SDCBUS(SendCmd)(sdcRegTags, bus) != -1) + { + D(bug("[SDCard%02ld] %s: Blocklen set to %d\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__, sdcRegTags[1].ti_Data)); + } + else + { + D(bug("[SDCard%02ld] %s: Failed to change Blocklen\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + } + } + AddBootNode(pp[DE_BOOTPRI + 4], ADNF_STARTPROC, devnode, NULL); + D(bug("[SDCard%02ld] %s: done\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return TRUE; + } + } + } + else + { + D(bug("[SDCard%02ld] %s: returned error (-1)\n", sdcUnit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + } + } + else + { + D(bug("[SDCard>>] %s: Failed to allocate Unit #%d\n", __PRETTY_FUNCTION__, bus->sdcb_UnitCnt)); + } + } + else + { + D(bug("error (-1)\n")); + } + } + else + { + D(bug("[SDCard>>] %s: returned error (-1)\n", __PRETTY_FUNCTION__)); + } + } + else + { + D(bug("[SDCard>>] %s: Failed to set card operating conditions\n", __PRETTY_FUNCTION__)); + } + } + else + { + D(bug("[SDCard>>] %s: returned error (-1)\n", __PRETTY_FUNCTION__)); + } + CloseLibrary((struct Library *)ExpansionBase); + } + else + { + } + + return FALSE; +} + +#define VCPOWER_SDHCI 0 +#define VCPOWER_STATE_ON (1 << 0) +#define VCPOWER_STATE_WAIT (1 << 1) +#define VCCLOCK_SDHCI 1 + +/* + * This init routine has +127 priority, so it runs after all + * bus scanners have done their job. + * It initializes all discovered units. + */ +static int FNAME_SDC(Scan)(struct SDCardBase *SDCardBase) +{ + unsigned int sdcReg = 0, sdcClkDiv, timeout = 10000, timeout_udelay; + + D(bug("[SDCard--] %s()\n", __PRETTY_FUNCTION__)); + + *(volatile unsigned int *)GPSET0 = (1 << 16); // Turn Activity LED OFF + + SDCardBase->sdcard_Bus->sdcb_IntrMask = SDHCI_INT_BUS_POWER | SDHCI_INT_DATA_END_BIT | + SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_INDEX | + SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT | + SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT | + SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | + SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE | + SDHCI_INT_ACMD12ERR; + + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_CLOCK_CONTROL, 0, SDCardBase->sdcard_Bus); + + D(bug("[SDCard--] %s: Setting Min Clock... ", __PRETTY_FUNCTION__)); + for (sdcClkDiv = 2; sdcClkDiv < V300_MAXCLKDIV; sdcClkDiv += 2) { + if ((SDCardBase->sdcard_Bus->sdcb_ClockMax / sdcClkDiv) <= HOSTCLOCK_MIN) + break; + } + sdcClkDiv >>= 1; + D(bug("div = %d\n", sdcClkDiv)); + + sdcReg = (sdcClkDiv & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; + sdcReg |= ((sdcClkDiv & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_CLOCK_CONTROL, (sdcReg | SDHCI_CLOCK_INT_EN), SDCardBase->sdcard_Bus); + + timeout = 20000; + while (!((sdcReg = FNAME_SDCBUS(MMIOReadWord)(SDHCI_CLOCK_CONTROL, SDCardBase->sdcard_Bus)) & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + D(bug("[SDCard--] %s: SDHCI Clock failed to stabilise\n", __PRETTY_FUNCTION__)); + break; + } + timeout_udelay = timeout - 1000; + for (; timeout > timeout_udelay; timeout --) asm volatile("mov r0, r0\n"); + } + D(bug("[SDCard--] %s: Enabling clock...\n", __PRETTY_FUNCTION__)); + sdcReg |= SDHCI_CLOCK_CARD_EN; + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_CLOCK_CONTROL, sdcReg, SDCardBase->sdcard_Bus); + + D(bug("[SDCard--] %s: Setting Power Lvl... ", __PRETTY_FUNCTION__)); + + if (SDCardBase->sdcard_Bus->sdcb_Power & MMC_VDD_165_195) + sdcReg = SDHCI_POWER_180; + else if (SDCardBase->sdcard_Bus->sdcb_Power & (MMC_VDD_290_300|MMC_VDD_300_310)) + sdcReg = SDHCI_POWER_300; + else if (SDCardBase->sdcard_Bus->sdcb_Power & (MMC_VDD_320_330|MMC_VDD_330_340)) + sdcReg = SDHCI_POWER_330; + else + sdcReg = 0; + + D(bug("%x\n", sdcReg)); + FNAME_SDCBUS(MMIOWriteByte)(SDHCI_POWER_CONTROL, sdcReg, SDCardBase->sdcard_Bus); + sdcReg |= SDHCI_POWER_ON; + FNAME_SDCBUS(MMIOWriteByte)(SDHCI_POWER_CONTROL, sdcReg, SDCardBase->sdcard_Bus); + + D(bug("[SDCard--] %s: Setting Min Buswidth...\n", __PRETTY_FUNCTION__)); + sdcReg = FNAME_SDCBUS(MMIOReadByte)(SDHCI_HOST_CONTROL, SDCardBase->sdcard_Bus); + sdcReg &= ~(SDHCI_HCTRL_4BITBUS|SDHCI_HCTRL_HISPD); + sdcReg |= SDHCI_HCTRL_4BITBUS; + FNAME_SDCBUS(MMIOWriteByte)(SDHCI_HOST_CONTROL, sdcReg, SDCardBase->sdcard_Bus); + + D(bug("[SDCard--] %s: Masking chipset Interrupts...\n", __PRETTY_FUNCTION__)); + + FNAME_SDCBUS(MMIOWriteLong)(SDHCI_INT_ENABLE, SDCardBase->sdcard_Bus->sdcb_IntrMask, SDCardBase->sdcard_Bus); + FNAME_SDCBUS(MMIOWriteLong)(SDHCI_SIGNAL_ENABLE, SDCardBase->sdcard_Bus->sdcb_IntrMask, SDCardBase->sdcard_Bus); + + D(bug("[SDCard--] %s: Launching Bus Task...\n", __PRETTY_FUNCTION__)); + + return NewCreateTask( + TASKTAG_PC , FNAME_SDCBUS(BusTask), + TASKTAG_NAME , "SDCard Subsystem", + TASKTAG_STACKSIZE , STACK_SIZE, + TASKTAG_PRI , TASK_PRI, + TASKTAG_TASKMSGPORT, &SDCardBase->sdcard_Bus->sdcb_MsgPort, + TASKTAG_ARG1 , SDCardBase->sdcard_Bus, + TAG_DONE) ? TRUE : FALSE; +} + +static int FNAME_SDC(Init)(struct SDCardBase *SDCardBase) +{ + D(bug("[SDCard--] %s()\n", __PRETTY_FUNCTION__)); + + if ((VCMBoxBase = OpenResource("vcmbox.resource")) == NULL) + { + D(bug("[SDCard--] %s: Failed to open vcmbox.resource\n", __PRETTY_FUNCTION__)); + return FALSE; + } + + LIBBASE->sdcard_MemPool = CreatePool(MEMF_CLEAR | MEMF_PUBLIC | MEMF_SEM_PROTECTED , 8192, 4096); + if (LIBBASE->sdcard_MemPool == NULL) + { + D(bug("[SDCard--] %s: Failed to Allocate MemPool\n", __PRETTY_FUNCTION__)); + return FALSE; + } + + D(bug("[SDCard--] %s: MemPool @ %p\n", __PRETTY_FUNCTION__, LIBBASE->sdcard_MemPool)); + + VCMBoxMessage[0] = 8 * 4; + VCMBoxMessage[1] = VCTAG_REQ; + VCMBoxMessage[2] = VCTAG_GETPOWER; + VCMBoxMessage[3] = 8; + VCMBoxMessage[4] = 4; + VCMBoxMessage[5] = VCPOWER_SDHCI; + VCMBoxMessage[6] = 0; + + VCMBoxMessage[7] = 0; // terminate tag + + VCMBoxWrite(VCMB_BASE, VCMB_PROPCHAN, VCMBoxMessage); + if (VCMBoxRead(VCMB_BASE, VCMB_PROPCHAN) != VCMBoxMessage) + { + D(bug("[SDCard--] %s: Failed to read controller's Power state\n", __PRETTY_FUNCTION__)); + return FALSE; + } + + if (!(VCMBoxMessage[6] & VCPOWER_STATE_ON)) + { + D(bug("[SDCard--] %s: Powering on Arasan SDHCI controller...\n", __PRETTY_FUNCTION__)); + + VCMBoxMessage[0] = 8 * 4; + VCMBoxMessage[1] = VCTAG_REQ; + VCMBoxMessage[2] = VCTAG_SETPOWER; + VCMBoxMessage[3] = 8; + VCMBoxMessage[4] = 8; + VCMBoxMessage[5] = VCPOWER_SDHCI; + VCMBoxMessage[6] = VCPOWER_STATE_ON | VCPOWER_STATE_WAIT; + + VCMBoxMessage[7] = 0; // terminate tag + + VCMBoxWrite(VCMB_BASE, VCMB_PROPCHAN, VCMBoxMessage); + if ((VCMBoxRead(VCMB_BASE, VCMB_PROPCHAN) != VCMBoxMessage) || (!(VCMBoxMessage[6] & VCPOWER_STATE_ON))) + { + D(bug("[SDCard--] %s: Failed to power on controller\n", __PRETTY_FUNCTION__)); + return FALSE; + } + } + + VCMBoxMessage[0] = 8 * 4; + VCMBoxMessage[1] = VCTAG_REQ; + VCMBoxMessage[2] = VCTAG_GETCLKRATE; + VCMBoxMessage[3] = 8; + VCMBoxMessage[4] = 4; + VCMBoxMessage[5] = VCCLOCK_SDHCI; + VCMBoxMessage[6] = 0; + + VCMBoxMessage[7] = 0; // terminate tag + + VCMBoxWrite(VCMB_BASE, VCMB_PROPCHAN, VCMBoxMessage); + if (VCMBoxRead(VCMB_BASE, VCMB_PROPCHAN) != VCMBoxMessage) + { + D(bug("[SDCard--] %s: Failed to determine Max SDHC Clock\n", __PRETTY_FUNCTION__)); + return FALSE; + } + + if ((LIBBASE->sdcard_Bus = AllocPooled(LIBBASE->sdcard_MemPool, sizeof(struct sdcard_Bus))) != NULL) + { + LIBBASE->sdcard_Bus->sdcb_DeviceBase = LIBBASE; + LIBBASE->sdcard_Bus->sdcb_IOBase = ARASAN_BASE; + LIBBASE->sdcard_Bus->sdcb_SectorShift = 9; + + LIBBASE->sdcard_Bus->sdcb_ClockMax = VCMBoxMessage[6]; + + D(bug("[SDCard--] %s: Reseting SDHCI...\n", __PRETTY_FUNCTION__)); + + FNAME_SDCBUS(SoftReset)(SDHCI_RESET_ALL, LIBBASE->sdcard_Bus); + + D(bug("[SDCard--] %s: SDHC Max Clock Rate : %dMHz\n", __PRETTY_FUNCTION__, LIBBASE->sdcard_Bus->sdcb_ClockMax / 1000000)); + D(bug("[SDCard--] %s: SDHC Min Clock Rate : %dHz (hardcoded)\n", __PRETTY_FUNCTION__, HOSTCLOCK_MIN)); + + LIBBASE->sdcard_Bus->sdcb_Version = FNAME_SDCBUS(MMIOReadWord)(SDHCI_HOST_VERSION, LIBBASE->sdcard_Bus); + LIBBASE->sdcard_Bus->sdcb_Capabilities = FNAME_SDCBUS(MMIOReadLong)(SDHCI_CAPABILITIES, LIBBASE->sdcard_Bus); + LIBBASE->sdcard_Bus->sdcb_Power = MMC_VDD_165_195 | MMC_VDD_320_330 | MMC_VDD_330_340; + + D(bug("[SDCard--] %s: SDHCI Host Vers : %d [SD Host Spec %d]\n", __PRETTY_FUNCTION__, ((LIBBASE->sdcard_Bus->sdcb_Version & 0xFF00) >> 8), (LIBBASE->sdcard_Bus->sdcb_Version & 0xFF) + 1)); + D(bug("[SDCard--] %s: SDHCI Capabilities : 0x%08x\n", __PRETTY_FUNCTION__, LIBBASE->sdcard_Bus->sdcb_Capabilities)); + D(bug("[SDCard--] %s: SDHCI Voltages : 0x%08x (hardcoded)\n", __PRETTY_FUNCTION__, LIBBASE->sdcard_Bus->sdcb_Power)); + + LIBBASE->sdcard_Bus->sdcb_LastWrite = *((volatile unsigned int *)(SYSTIMER_CLO)); + } + return TRUE; +} + +static int FNAME_SDC(Open) +( + LIBBASETYPEPTR LIBBASE, + struct IORequest *iorq, + ULONG unitnum, + ULONG flags +) +{ + unsigned int sdcReg = 0, sdcClkDiv, timeout = 10000, timeout_udelay; + + D(bug("[SDCard--] %s()\n", __PRETTY_FUNCTION__)); + + /* Assume it failed */ + iorq->io_Error = IOERR_OPENFAIL; + + if ((unitnum < LIBBASE->sdcard_Bus->sdcb_UnitCnt) && (LIBBASE->sdcard_Bus->sdcb_Units[unitnum])) + { + struct TagItem sdcOpenTags[] = + { + {SDCARD_TAG_CMD, MMC_CMD_SELECT_CARD}, + {SDCARD_TAG_ARG, LIBBASE->sdcard_Bus->sdcb_Units[unitnum]->sdcu_CardRCA << 16}, + {SDCARD_TAG_RSPTYPE, MMC_RSP_R1}, + {SDCARD_TAG_RSP, 0}, + {TAG_DONE, 0} + }; + if (FNAME_SDCBUS(SendCmd)(sdcOpenTags, LIBBASE->sdcard_Bus) != -1) + { + iorq->io_Unit = &LIBBASE->sdcard_Bus->sdcb_Units[unitnum]->sdcu_Unit; + ((struct sdcard_Unit *)iorq->io_Unit)->sdcu_Unit.unit_OpenCnt++; + + D(bug("[SDCard%02ld] %s: Selected card with RCA %d\n", unitnum, __PRETTY_FUNCTION__, LIBBASE->sdcard_Bus->sdcb_Units[unitnum]->sdcu_CardRCA)); + D(bug("[SDCard%02ld] %s: Card is now operating in Transfer Mode\n", unitnum, __PRETTY_FUNCTION__)); + + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_CLOCK_CONTROL, 0, LIBBASE->sdcard_Bus); + + D(bug("[SDCard%02ld] %s: Setting Clock... ", unitnum, __PRETTY_FUNCTION__)); + for (sdcClkDiv = 2; sdcClkDiv < V300_MAXCLKDIV; sdcClkDiv += 2) { + if ((LIBBASE->sdcard_Bus->sdcb_ClockMax / sdcClkDiv) <= 25000000) + break; + } + sdcClkDiv >>= 1; + D(bug("div = %d\n", sdcClkDiv)); + + sdcReg = (sdcClkDiv & SDHCI_DIV_MASK) << SDHCI_DIVIDER_SHIFT; + sdcReg |= ((sdcClkDiv & SDHCI_DIV_HI_MASK) >> SDHCI_DIV_MASK_LEN) << SDHCI_DIVIDER_HI_SHIFT; + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_CLOCK_CONTROL, (sdcReg | SDHCI_CLOCK_INT_EN), LIBBASE->sdcard_Bus); + + timeout = 20000; + while (!((sdcReg = FNAME_SDCBUS(MMIOReadWord)(SDHCI_CLOCK_CONTROL, LIBBASE->sdcard_Bus)) & SDHCI_CLOCK_INT_STABLE)) { + if (timeout == 0) { + D(bug("[SDCard%02ld] %s: SDHCI Clock failed to stabilise\n", unitnum, __PRETTY_FUNCTION__)); + break; + } + timeout_udelay = timeout - 1000; + for (; timeout > timeout_udelay; timeout --) asm volatile("mov r0, r0\n"); + } + D(bug("[SDCard%02ld] %s: Enabling clock...\n", unitnum, __PRETTY_FUNCTION__)); + sdcReg |= SDHCI_CLOCK_CARD_EN; + FNAME_SDCBUS(MMIOWriteWord)(SDHCI_CLOCK_CONTROL, sdcReg, LIBBASE->sdcard_Bus); + + iorq->io_Error = 0; + } + } + return iorq->io_Error ? FALSE : TRUE; +} + +/* Close given device */ +static int FNAME_SDC(Close) +( + LIBBASETYPEPTR LIBBASE, + struct IORequest *iorq +) +{ + struct sdcard_Unit *unit = (struct sdcard_Unit *)iorq->io_Unit; + + D(bug("[SDCard--] %s()\n", __PRETTY_FUNCTION__)); + + /* First of all make the important fields of struct IORequest invalid! */ + iorq->io_Unit = (struct Unit *)~0; + + /* Decrease use counters of unit */ + unit->sdcu_Unit.unit_OpenCnt--; + + return TRUE; +} + +ADD2INITLIB(FNAME_SDC(Init), 0) +ADD2INITLIB(FNAME_SDC(Scan), 127) +ADD2OPENDEV(FNAME_SDC(Open), 0) +ADD2CLOSEDEV(FNAME_SDC(Close), 0) diff --git a/arch/arm-raspi/devs/sdcard/sdcard_intern.h b/arch/arm-raspi/devs/sdcard/sdcard_intern.h new file mode 100644 index 0000000000..0410c5f6b7 --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/sdcard_intern.h @@ -0,0 +1,204 @@ +#ifndef _SDCARD_INTERN_H +#define _SDCARD_INTERN_H +/* + Copyright © 2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FNAME_SDC(x) SDCARD__Device__ ## x +#define FNAME_SDCIO(x) SDCARD__SDIO__ ## x +#define FNAME_SDCBUS(x) SDCARD__SDBus__ ## x + +#define TASK_PRI 10 +#define TIMEOUT 30 + +#define HOSTCLOCK_MIN 400000 +#define V200_MAXCLKDIV 256 +#define V300_MAXCLKDIV 2046 + +#define SDCARD_TAGBASE (TAG_USER | 0x00534400) + +#define SDCARD_TAG_CMD (SDCARD_TAGBASE + 1) +#define SDCARD_TAG_ARG (SDCARD_TAGBASE + 2) +#define SDCARD_TAG_RSPTYPE (SDCARD_TAGBASE + 3) +#define SDCARD_TAG_RSP (SDCARD_TAGBASE + 4) +#define SDCARD_TAG_DATA (SDCARD_TAGBASE + 5) +#define SDCARD_TAG_DATALEN (SDCARD_TAGBASE + 6) +#define SDCARD_TAG_DATAFLAGS (SDCARD_TAGBASE + 7) + +/* structure forward declarations */ +struct sdcard_Unit; +struct sdcard_Bus; + +/* sdhc.device base */ +struct SDCardBase +{ + /* standard device structure */ + struct Device sdcard_Device; + + /* Imports */ + struct Device *sdcard_TimerBase; + APTR sdcard_VCMBoxBase; + + /* Bus's (to be replaced with hidds...) */ + struct sdcard_Bus *sdcard_Bus; + + /* Memory Management */ + APTR sdcard_MemPool; +}; + +struct sdcard_Bus +{ + struct SDCardBase *sdcb_DeviceBase; /* Device self */ + + APTR sdcb_IOBase; + ULONG sdcb_BusNum; + + UBYTE sdcb_BusFlags; /* Bus flags similar to unit flags */ + UBYTE sdcb_TaskSig; /* Signal used to wake task */ + UBYTE sdcb_SectorShift; /* Sector shift. 9 here is 512 bytes sector */ + + struct Task *sdcb_Task; + struct MsgPort *sdcb_MsgPort; + struct IORequest *sdcb_Timer; /* timer stuff */ + + /* Chipset .. */ + ULONG sdcb_Capabilities; + ULONG sdcb_Version; + ULONG sdcb_ClockMax; + ULONG sdcb_Power; + + ULONG sdcb_IntrMask; + + ULONG sdcb_LastWrite; + + ULONG sdcb_UnitCnt; + struct sdcard_Unit *sdcb_Units[1]; /* Units on the bus */ +}; + +/* + Unit structure describing given device on the bus. It contains all the + necessary information unit/device may need. + */ +struct sdcard_Unit +{ + struct Unit sdcu_Unit; /* exec's unit */ + struct sdcard_Bus *sdcu_Bus; /* Bus on which this unit is */ + ULONG sdcu_Flags; /* Unit flags, see below */ + ULONG sdcu_UnitNum; /* Unit number as coded by device */ + ULONG sdcu_CardRCA; + + UQUAD sdcu_Capacity; /* Real capacity of device */ + +/* OLD DEFINES */ + + ULONG sdcu_DMAPort; + + ULONG sdcu_Cylinders; + UBYTE sdcu_Heads; + UBYTE sdcu_Sectors; + UBYTE sdcu_Model[41]; + UBYTE sdcu_FirmwareRev[9]; + UBYTE sdcu_SerialNumber[21]; + + /* + Here are stored pointers to functions responsible for handling this + device. They are set during device initialization and point to most + effective functions for this particular unit. Read/Write may be done + in PIO mode reading single sectors, using multisector PIO, or + multiword DMA. + */ + BYTE (*sdcu_Read32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); + BYTE (*sdcu_Write32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); + BYTE (*sdcu_Read64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); + BYTE (*sdcu_Write64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); + BYTE (*sdcu_Eject)(struct sdcard_Unit *); + BYTE (*sdcu_DirectSCSI)(struct sdcard_Unit *, struct SCSICmd*); + + ULONG sdcu_ChangeNum; /* Number of disc changes */ + + struct Interrupt *sdcu_RemoveInt; /* Raise this interrupt on a disc change */ + struct List sdcu_SoftList; /* Raise even more interrupts from this list on disc change */ + + UBYTE sdcu_DevMask; /* device mask used to simplify device number coding */ + UBYTE sdcu_SenseKey; /* Sense key from ATAPI devices */ + UBYTE sdcu_DevType; + + /******* PIO IO ********/ + APTR sdcu_cmd_data; + ULONG sdcu_cmd_length; + ULONG sdcu_cmd_total; + ULONG sdcu_cmd_error; +}; + +/* Unit internal flags */ +#define AB_MediaPresent 30 /* media available */ +#define AB_MediaChanged 29 /* media changed */ +#define AB_HighSpeed 28 +#define AB_HighCapacity 27 +#define AB_MMC 26 +#define AB_4bitData 25 + +#define AF_MediaPresent (1 << AB_MediaPresent) +#define AF_MediaChanged (1 << AB_MediaChanged) +#define AF_HighSpeed (1 << AB_HighSpeed) +#define AF_HighCapacity (1 << AB_HighCapacity) +#define AF_MMC (1 << AB_MMC) +#define AF_4bitData (1 << AB_4bitData) + +#define Unit(io) ((struct sdcard_Unit *)(io)->io_Unit) +#define IOStdReq(io) ((struct IOStdReq *)io) + +UBYTE FNAME_SDCBUS(MMIOReadByte)(ULONG, struct sdcard_Bus *); +UWORD FNAME_SDCBUS(MMIOReadWord)(ULONG, struct sdcard_Bus *); +ULONG FNAME_SDCBUS(MMIOReadLong)(ULONG, struct sdcard_Bus *); + +void FNAME_SDCBUS(MMIOWriteByte)(ULONG, UBYTE, struct sdcard_Bus *); +void FNAME_SDCBUS(MMIOWriteWord)(ULONG, UWORD, struct sdcard_Bus *); +void FNAME_SDCBUS(MMIOWriteLong)(ULONG, ULONG, struct sdcard_Bus *); + +void FNAME_SDCBUS(SoftReset)(UBYTE, struct sdcard_Bus *); +ULONG FNAME_SDCBUS(SendCmd)(struct TagItem *, struct sdcard_Bus *); +ULONG FNAME_SDCBUS(Rsp136Unpack)(ULONG *, ULONG, const ULONG); + +void FNAME_SDCBUS(BusTask)(struct sdcard_Bus *); + +BOOL FNAME_SDC(RegisterVolume)(struct sdcard_Bus *); + +int FNAME_SDCBUS(SDUnitChangeFrequency)(struct sdcard_Unit *); + +BOOL FNAME_SDC(HandleIO)(struct IORequest *io); + +/* IO Operations */ + +BYTE FNAME_SDCIO(ReadSector32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(ReadSector64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(ReadMultiple32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(ReadMultiple64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(ReadDMA32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(ReadDMA64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(WriteSector32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(WriteSector64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(WriteMultiple32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(WriteMultiple64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(WriteDMA32)(struct sdcard_Unit *, ULONG, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(WriteDMA64)(struct sdcard_Unit *, UQUAD, ULONG, APTR, ULONG *); +BYTE FNAME_SDCIO(Eject)(struct sdcard_Unit *); + +#endif // _SDCARD_INTERN_H + diff --git a/arch/arm-raspi/devs/sdcard/sdcard_ioops.c b/arch/arm-raspi/devs/sdcard/sdcard_ioops.c new file mode 100644 index 0000000000..d448cdbc3c --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/sdcard_ioops.c @@ -0,0 +1,324 @@ +/* + Copyright © 2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 + +// use #define xxx(a) D(a) to enable particular sections. +#if DEBUG +#define DIRQ(a) D(a) +#define DIRQ_MORE(a) +#define DUMP(a) D(a) +#define DUMP_MORE(a) +#define DINIT(a) (a) +#else +#define DIRQ(a) do { } while (0) +#define DIRQ_MORE(a) do { } while (0) +#define DUMP(a) do { } while (0) +#define DUMP_MORE(a) do { } while (0) +#define DINIT(a) do { } while (0) +#endif +/* Errors that shouldn't happen */ +#define DERROR(a) a + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "sdcard_intern.h" +#include "timer.h" + +static BOOL sdcard_WaitBusyTO(struct sdcard_Unit *unit, UWORD tout, BOOL irq, UBYTE *stout); + +#define DEVHEAD_VAL 0x40 + +#if DEBUG +static void dump(APTR mem, ULONG len) +{ + register int i, j = 0; + + DUMP_MORE(for (j=0; j<(len+15)>>4; ++j)) + { + bug("[SDC ] %06lx: ", j<<4); + + for (i=0; i= 0x20 ? c<=0x7f ? c : '.' : '.'); + if (i == 15) + break; + } + bug("\n"); + } +} +#endif + +static void sdcard_strcpy(const UBYTE *str1, UBYTE *str2, ULONG size) +{ + register int i = size; + + while (size--) + str2[size ^ 1] = str1[size]; + + while (i > 0 && str2[--i] <= ' ') + str2[i] = '\0'; +} + +/* + * a STUB function for commands not supported by this particular device + */ +static BYTE sdcard_STUB(struct sdcard_Unit *unit) +{ + DERROR(bug("[SDCard%02ld] CALLED STUB FUNCTION (GENERIC). OPERATION IS NOT SUPPORTED BY DEVICE\n", unit->sdcu_UnitNum)); + return CDERR_NOCMD; +} + +static BYTE sdcard_STUB_IO32(struct sdcard_Unit *unit, ULONG blk, ULONG len, + APTR buf, ULONG* act) +{ + DERROR(bug("[SDCard%02ld] CALLED STUB FUNCTION (IO32). OPERATION IS NOT SUPPORTED BY DEVICE\n", unit->sdcu_UnitNum)); + DERROR(bug("[SDCard%02ld] -- IO ACCESS TO BLOCK %08lx, LENGTH %08lx\n", unit->sdcu_UnitNum, blk, len)); + return CDERR_NOCMD; +} + +static BYTE sdcard_STUB_IO64(struct sdcard_Unit *unit, UQUAD blk, ULONG len, + APTR buf, ULONG* act) +{ + DERROR(bug("[SDCard%02ld] CALLED STUB FUNCTION (IO64). OPERATION IS NOT SUPPORTED BY DEVICE\n", unit->sdcu_UnitNum)); + DERROR(bug("[SDCard%02ld] -- IO ACCESS TO BLOCK %08lx:%08lx, LENGTH %08lx\n", unit->sdcu_UnitNum, (blk >> 32), (blk & 0xffffffff), len)); + return CDERR_NOCMD; +} + +static BYTE sdcard_STUB_SCSI(struct sdcard_Unit *unit, struct SCSICmd* cmd) +{ + DERROR(bug("[SDCard%02ld] CALLED STUB FUNCTION (IOSCSI). OPERATION IS NOT SUPPORTED BY DEVICE\n", unit->sdcu_UnitNum)); + return CDERR_NOCMD; +} + +static inline BOOL sdcard_SelectUnit(struct sdcard_Unit* unit) +{ + return TRUE; +} + +void sdcard_IRQSetHandler(struct sdcard_Unit *unit, void (*handler)(struct sdcard_Unit*, UBYTE), APTR piomem, ULONG blklen, ULONG piolen) +{ + +} + +void sdcard_IRQNoData(struct sdcard_Unit *unit, UBYTE status) +{ + +} + +void sdcard_IRQPIORead(struct sdcard_Unit *unit, UBYTE status) +{ + +} + +void sdcard_PIOWriteBlk(struct sdcard_Unit *unit) +{ + +} + +void sdcard_IRQPIOWrite(struct sdcard_Unit *unit, UBYTE status) +{ + +} + +void sdcard_IRQDMAReadWrite(struct sdcard_Unit *unit, UBYTE status) +{ + +} + +/* + * wait for timeout or drive ready + */ +BOOL sdcard_WaitBusyTO(struct sdcard_Unit *unit, UWORD tout, BOOL irq, UBYTE *stout) +{ + BYTE err = 0; + return err; +} + +/* + * 32bit Read operations + */ +BYTE FNAME_SDCIO(ReadSector32)(struct sdcard_Unit *unit, ULONG block, + ULONG count, APTR buffer, ULONG *act) +{ + struct TagItem sdcReadTags[] = + { + {SDCARD_TAG_CMD, MMC_CMD_READ_SINGLE_BLOCK}, + {SDCARD_TAG_ARG, block}, + {SDCARD_TAG_RSPTYPE, MMC_RSP_R1}, + {SDCARD_TAG_RSP, 0}, + {SDCARD_TAG_DATA, buffer}, + {SDCARD_TAG_DATALEN, count * (1 << unit->sdcu_Bus->sdcb_SectorShift)}, + {SDCARD_TAG_DATAFLAGS, MMC_DATA_READ}, + {TAG_DONE, 0} + }; + + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + *act = 0; + + if (count > 1) + sdcReadTags[0].ti_Data = MMC_CMD_READ_MULTIPLE_BLOCK; + + if (!(unit->sdcu_Flags & AF_HighCapacity)) + sdcReadTags[1].ti_Data <<= unit->sdcu_Bus->sdcb_SectorShift; + + D(bug("[SDCard%02ld] %s: Sending CMD %d, block 0x%p, len %d [buffer @ 0x%p]\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__, + sdcReadTags[0].ti_Data, sdcReadTags[1].ti_Data, sdcReadTags[5].ti_Data, sdcReadTags[4].ti_Data)); + + if (FNAME_SDCBUS(SendCmd)(sdcReadTags, unit->sdcu_Bus) != -1) + { + D(bug("[SDCard%02ld] %s: checking response ..\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + } + else + { + D(bug("[SDCard%02ld] %s: Error ..\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + count = 0; + } + + if (count > 1) + { + sdcReadTags[0].ti_Data = MMC_CMD_STOP_TRANSMISSION; + sdcReadTags[1].ti_Data = 0; + sdcReadTags[1].ti_Data = MMC_RSP_R1b; + if (FNAME_SDCBUS(SendCmd)(sdcReadTags, unit->sdcu_Bus) == -1) + { + D(bug("[SDCard%02ld] %s: Failed to terminate Read operation\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + } + } + + *act = count << unit->sdcu_Bus->sdcb_SectorShift; + + D(bug("[SDCard%02ld] %s: %d bytes Read\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__, *act)); + + return 0; +} + +BYTE FNAME_SDCIO(ReadMultiple32)(struct sdcard_Unit *unit, ULONG block, + ULONG count, APTR buffer, ULONG *act) +{ + + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +BYTE FNAME_SDCIO(ReadDMA32)(struct sdcard_Unit *unit, ULONG block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +/* + * 64bit Read operations + */ +BYTE FNAME_SDCIO(ReadSector64)(struct sdcard_Unit *unit, UQUAD block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +BYTE FNAME_SDCIO(ReadMultiple64)(struct sdcard_Unit *unit, UQUAD block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +BYTE FNAME_SDCIO(ReadDMA64)(struct sdcard_Unit *unit, UQUAD block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +/* + * 32bit Write operations + */ +BYTE FNAME_SDCIO(WriteSector32)(struct sdcard_Unit *unit, ULONG block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +BYTE FNAME_SDCIO(WriteMultiple32)(struct sdcard_Unit *unit, ULONG block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +BYTE FNAME_SDCIO(WriteDMA32)(struct sdcard_Unit *unit, ULONG block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +/* + * 64bit Write operations + */ +BYTE FNAME_SDCIO(WriteSector64)(struct sdcard_Unit *unit, UQUAD block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +BYTE FNAME_SDCIO(WriteMultiple64)(struct sdcard_Unit *unit, UQUAD block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +BYTE FNAME_SDCIO(WriteDMA64)(struct sdcard_Unit *unit, UQUAD block, + ULONG count, APTR buffer, ULONG *act) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} + +/* + * miscellaneous + */ +BYTE FNAME_SDCIO(Eject)(struct sdcard_Unit *unit) +{ + D(bug("[SDCard%02ld] %s()\n", unit->sdcu_UnitNum, __PRETTY_FUNCTION__)); + + return 0; +} diff --git a/arch/arm-raspi/devs/sdcard/timer.c b/arch/arm-raspi/devs/sdcard/timer.c new file mode 100644 index 0000000000..180cfbecfc --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/timer.c @@ -0,0 +1,105 @@ +/* + Copyright © 2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +#define DEBUG 1 +#include + +#include +#include +#include +#include +#include +#include + +#include "timer.h" +#include "sdcard_intern.h" + +struct IORequest *sdcard_OpenTimer(struct SDCardBase *SDCardBase) +{ + struct MsgPort *p = CreateMsgPort(); + if (NULL != p) + { + struct IORequest *io = CreateIORequest(p, sizeof(struct timerequest)); + + if (NULL != io) + { + /* + * ok. ECLOCK does not have too great resolution, either. + * we will have to sacrifice our performance a little bit, meaning, the 400ns will turn into (worst case) 2us. + * hopefully we won't have to call that TOO often... + */ + if (0 == OpenDevice("timer.device", UNIT_MICROHZ, io, 0)) + { + if (NULL == SDCardBase->sdcard_TimerBase) + { + SDCardBase->sdcard_TimerBase = io->io_Device; + } + return io; + } + else + { + bug("[SDCard ] Failed to open timer.device, unit MICROHZ\n"); + } + DeleteIORequest(io); + } + else + { + bug("[SDCard ] Failed to create timerequest\n"); + } + DeleteMsgPort(p); + } + else + { + bug("[SDCard ] Failed to create timer port\n"); + } + + return NULL; +} + +void sdcard_CloseTimer(struct IORequest *tmr) +{ + if (NULL != tmr) + { + struct MsgPort *p = tmr->io_Message.mn_ReplyPort; + CloseDevice(tmr); + DeleteIORequest(tmr); + DeleteMsgPort(p); + } +} + +void sdcard_WaitNano(register ULONG ns, struct SDCardBase *SDCardBase) +{ + volatile register ULONG t = 1; + while (ns > 0) + { + asm volatile("mov r0, r0\n"); + --ns; + } +} + +ULONG sdcard_WaitTO(struct IORequest* tmr, ULONG secs, ULONG micro, ULONG sigs) +{ + ULONG sig = 1 << tmr->io_Message.mn_ReplyPort->mp_SigBit; + + //D(bug("[SDCard--] Timed wait %lds %ldu\n", secs, micro)); + + tmr->io_Command = TR_ADDREQUEST; + ((struct timerequest*)tmr)->tr_time.tv_secs = secs; + ((struct timerequest*)tmr)->tr_time.tv_micro = micro; + + SendIO(tmr); + sigs = Wait(sigs | sig); + if (0 == (sigs & sig)) + { + if (!CheckIO(tmr)) + AbortIO(tmr); + } + WaitIO(tmr); + + SetSignal(0, sig); + + return sigs &~ sig; +} + diff --git a/arch/arm-raspi/devs/sdcard/timer.h b/arch/arm-raspi/devs/sdcard/timer.h new file mode 100644 index 0000000000..eebcac3663 --- /dev/null +++ b/arch/arm-raspi/devs/sdcard/timer.h @@ -0,0 +1,52 @@ +/* + Copyright © 2013, The AROS Development Team. All rights reserved. + $Id$ +*/ + +struct SDCardBase; + +/* + * sdcard_OpenTimer + * create timerequest to manage timed operations + * result + * timerequest to be used with any of the calls below + * note + * only one task can use given timerequest + */ +struct IORequest *sdcard_OpenTimer(struct SDCardBase *SDCardBase); + +/* + * sdcard_CloseTimer + * dispose timerequest; most likely never used ;) + * params + * tmr - obtained via sdcard_OpenTimer() + * result + * none + */ +void sdcard_CloseTimer(struct IORequest *tmr); + +/* + * sdcard_Wait + * wait for a period of time or a signal + * params + * tmr - obtained via sdcard_OpenTimer() + * secs - number of seconds to wait + * micro - number of microseconds to wait + * sigs - additionally - signal to wait for + * result + * ULONG signals - if caught before timeout + */ +ULONG sdcard_WaitTO(struct IORequest* tmr, ULONG secs, ULONG micro, ULONG sigs); + +/* + * sdcard_WaitNano + * waits for (pretty much) specified amount of time. benchmarked. + * params + * ns - amount of nanoseconds; + * result + * none + * note + * rounds up ns to nearest multiple of 100 + */ +void sdcard_WaitNano(ULONG ns, struct SDCardBase *SDCardBase); + -- 2.11.4.GIT