diff --git a/Makefile b/Makefile index 5664ead..af85377 100644 --- a/Makefile +++ b/Makefile @@ -14,7 +14,7 @@ TARGET_BIN = armboot.bin OBJS = start.o main.o ipc.o vsprintf.o string.o gecko.o memory.o memory_asm.o \ utils_asm.o utils.o ff.o diskio.o sdhc.o powerpc_elf.o powerpc.o panic.o \ irq.o irq_asm.o exception.o exception_asm.o seeprom.o crypto.o nand.o \ - boot2.o ldhack.o + boot2.o ldhack.o sdmmc.o include ../../common.mk diff --git a/bsdtypes.h b/bsdtypes.h index b752b2e..56d28a1 100644 --- a/bsdtypes.h +++ b/bsdtypes.h @@ -24,6 +24,6 @@ struct device { #define bzero(mem, size) memset(mem, 0, size) -#define ISSET(var, mask) (((var) & (mask)) == (mask) ? 1 : 0) +#define ISSET(var, mask) (((var) & (mask)) ? 1 : 0) #define SET(var, mask) ((var) |= (mask)) #endif diff --git a/ipc.c b/ipc.c index b3eafd4..2b0a927 100644 --- a/ipc.c +++ b/ipc.c @@ -30,7 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "gecko.h" #include "ipc.h" #include "nand.h" -//#include "sdhc.h" +#include "sdhcvar.h" #include "crypto.h" #include "boot2.h" #include "powerpc.h" @@ -150,7 +150,7 @@ static u32 process_slow(volatile ipc_request *req) nand_ipc(req); break; case IPC_DEV_SD: -// sd_ipc(req); + sdhc_ipc(req); break; case IPC_DEV_KEYS: crypto_ipc(req); @@ -171,6 +171,16 @@ static u32 process_slow(volatile ipc_request *req) return 0; } +void ipc_add_slow(volatile ipc_request *req) +{ + if(slow_queue_head == ((slow_queue_tail + 1)&(IPC_SLOW_SIZE-1))) { + gecko_printf("IPC: Slowqueue overrun\n"); + panic2(0, PANIC_IPCOVF); + } + slow_queue[slow_queue_tail] = *req; + slow_queue_tail = (slow_queue_tail+1)&(IPC_SLOW_SIZE-1); +} + static void process_in(void) { volatile ipc_request *req = &in_queue[in_head]; @@ -245,12 +255,7 @@ static void process_in(void) break; } } else { - if(slow_queue_head == ((slow_queue_tail + 1)&(IPC_SLOW_SIZE-1))) { - gecko_printf("IPC: Slowqueue overrun\n"); - panic2(0, PANIC_IPCOVF); - } - slow_queue[slow_queue_tail] = *req; - slow_queue_tail = (slow_queue_tail+1)&(IPC_SLOW_SIZE-1); + ipc_add_slow(req); } } diff --git a/ipc.h b/ipc.h index fd84717..827b16c 100644 --- a/ipc.h +++ b/ipc.h @@ -62,12 +62,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #define IPC_NAND_ERASE 0x0004 #define IPC_NAND_STATUS 0x0005 -#define IPC_SD_MOUNT 0x0000 +/*#define IPC_SD_MOUNT 0x0000 #define IPC_SD_SELECT 0x0001 #define IPC_SD_GETSTATE 0x0002 -#define IPC_SD_READ 0x0003 +#define IPC_SD_READ 0x0003 #define IPC_SD_WRITE 0x0004 -#define IPC_SD_GETSIZE 0x0005 +#define IPC_SD_GETSIZE 0x0005*/ #define IPC_KEYS_GETOTP 0x0000 #define IPC_KEYS_GETEEP 0x0001 @@ -120,4 +120,8 @@ void ipc_post(u32 code, u32 tag, u32 num_args, ...); void ipc_flush(void); u32 ipc_process_slow(void); +// add an entry to the slow queue from the arm +// (you probably want to use this in irq context) +void ipc_add_slow(volatile ipc_request *req); + #endif diff --git a/main.c b/main.c index eb8520b..f0c447c 100644 --- a/main.c +++ b/main.c @@ -187,7 +187,7 @@ u32 _main(void *base) irq_initialize(); irq_enable(IRQ_TIMER); - irq_enable(IRQ_GPIO1B); +// irq_enable(IRQ_GPIO1B); irq_enable(IRQ_GPIO1); irq_enable(IRQ_RESET); gecko_timer_initialize(); diff --git a/mini.ld b/mini.ld index fc5b15e..acb27b1 100644 --- a/mini.ld +++ b/mini.ld @@ -5,7 +5,7 @@ EXTERN(__ipc_info) ENTRY(_start) __stack_size = 0x800; -__irqstack_size = 0x100; +__irqstack_size = 0x400; /* blame the bsd's sdhc_intr function */ __excstack_size = 0x100; MEMORY { diff --git a/sdhc.c b/sdhc.c index 236526c..0ec37f8 100644 --- a/sdhc.c +++ b/sdhc.c @@ -2,6 +2,7 @@ /* * Copyright (c) 2006 Uwe Stuehler + * Copyright (c) 2009 Sven Peter * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -37,31 +38,19 @@ #include "sdmmcchip.h" #include "sdmmcreg.h" #include "sdmmcvar.h" +#include "sdmmc.h" #include "gecko.h" #include "string.h" #include "irq.h" #include "utils.h" +#include "ipc.h" -#define SDHC_DEBUG 1 +#define SDHC_DEBUG 0 #define SDHC_COMMAND_TIMEOUT 0 #define SDHC_BUFFER_TIMEOUT 0 #define SDHC_TRANSFER_TIMEOUT 0 -struct sdhc_host { - struct sdhc_softc *sc; /* host controller device */ - struct device *sdmmc; /* generic SD/MMC device */ - bus_space_tag_t iot; /* host register set tag */ - bus_space_handle_t ioh; /* host register set handle */ - u_int clkbase; /* base clock frequency in KHz */ - int maxblklen; /* maximum block length */ - int flags; /* flags for this host */ - u_int32_t ocr; /* OCR value from capabilities */ - u_int8_t regs[14]; /* host controller state */ - u_int16_t intr_status; /* soft interrupt status */ - u_int16_t intr_error_status; /* soft error status */ -}; - #define HDEVNAME(hp) ((hp)->sc->sc_dev.dv_xname) #define sdmmc_delay(t) udelay(t) @@ -119,13 +108,13 @@ static inline void bus_space_write_1(bus_space_tag_t iot, bus_space_handle_t ioh u32 splbio() { - irq_disable(IRQ_SDHC); +// irq_disable(IRQ_SDHC); return 0; } void splx(u32 dummy) { - irq_enable(IRQ_SDHC); +// irq_enable(IRQ_SDHC); } /* flag values */ @@ -213,6 +202,8 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, struct sdhc_host *hp; u_int32_t caps; int error = 1; + + strcpy(sc->sc_dev.dv_xname, "sdhc"); #ifdef SDHC_DEBUG u_int16_t version; @@ -232,7 +223,7 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, /* Allocate one more host structure. */ if (sc->sc_nhosts < SDHC_MAX_HOSTS) { sc->sc_nhosts++; - hp = sc->sc_host[sc->sc_nhosts - 1]; + hp = &sc->sc_host[sc->sc_nhosts - 1]; memset(hp, 0, sizeof(*hp)); } else @@ -315,6 +306,7 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, saa.sct = &sdhc_functions; saa.sch = hp; + hp->sdmmc = sdmmc_attach(&sdhc_functions, hp, "sdhc", ioh); /* hp->sdmmc = config_found(&sc->sc_dev, &saa, NULL); if (hp->sdmmc == NULL) { error = 0; @@ -325,7 +317,6 @@ sdhc_host_found(struct sdhc_softc *sc, bus_space_tag_t iot, err: // free(hp, M_DEVBUF); - sc->sc_host[sc->sc_nhosts - 1] = NULL; sc->sc_nhosts--; return (error); } @@ -380,7 +371,7 @@ sdhc_shutdown(void *arg) /* XXX chip locks up if we don't disable it before reboot. */ for (i = 0; i < sc->sc_nhosts; i++) { - hp = sc->sc_host[i]; + hp = &sc->sc_host[i]; (void)sdhc_host_reset(hp); } } @@ -967,7 +958,7 @@ sdhc_intr(void *arg) /* We got an interrupt, but we don't know from which slot. */ for (host = 0; host < sc->sc_nhosts; host++) { - struct sdhc_host *hp = sc->sc_host[host]; + struct sdhc_host *hp = &sc->sc_host[host]; u_int16_t status; if (hp == NULL) @@ -983,6 +974,7 @@ sdhc_intr(void *arg) DPRINTF(2,("%s: interrupt status=%d\n", HDEVNAME(hp), status)); + /* Claim this interrupt. */ done = 1; @@ -1008,9 +1000,11 @@ sdhc_intr(void *arg) /* * Wake up the sdmmc event thread to scan for cards. + * TODO: move request to slow queue to make sure that + * we're not blocking other IRQs */ -/* if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) - sdmmc_needs_discover(hp->sdmmc);*/ + if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) + sdmmc_needs_discover(hp->sdmmc); /* * Wake up the blocking process to service command @@ -1067,13 +1061,21 @@ static struct sdhc_softc __softc; void sdhc_irq(void) { + ipc_request req; sdhc_intr(&__softc); } void sdhc_init(void) { + irq_enable(IRQ_SDHC); memset(&__softc, 0, sizeof(__softc)); sdhc_host_found(&__softc, 0, SDHC_REG_BASE, 1); // sdhc_host_found(&__softc, 0, SDHC_REG_BASE + 0x100, 1); // sdhc_host_found(&__softc, 0, 0x0d080000, 1); } + +void sdhc_ipc(volatile ipc_request *req) +{ + switch (req->req) { + } +} diff --git a/sdhcvar.h b/sdhcvar.h index afdd444..c70f904 100644 --- a/sdhcvar.h +++ b/sdhcvar.h @@ -21,13 +21,26 @@ #define _SDHCVAR_H_ #include "bsdtypes.h" +#include "ipc.h" #define SDHC_MAX_HOSTS 4 -struct sdhc_host; +struct sdhc_host { + struct sdhc_softc *sc; /* host controller device */ + struct device *sdmmc; /* generic SD/MMC device */ + bus_space_tag_t iot; /* host register set tag */ + bus_space_handle_t ioh; /* host register set handle */ + u_int clkbase; /* base clock frequency in KHz */ + int maxblklen; /* maximum block length */ + int flags; /* flags for this host */ + u_int32_t ocr; /* OCR value from capabilities */ + u_int8_t regs[14]; /* host controller state */ + u_int16_t intr_status; /* soft interrupt status */ + u_int16_t intr_error_status; /* soft error status */ +}; struct sdhc_softc { struct device sc_dev; - struct sdhc_host *sc_host[SDHC_MAX_HOSTS]; + struct sdhc_host sc_host[SDHC_MAX_HOSTS]; int sc_nhosts; u_int sc_flags; }; @@ -41,6 +54,7 @@ void sdhc_shutdown(void *); int sdhc_intr(void *); void sdhc_init(void); void sdhc_irq(void); +void sdhc_ipc(volatile ipc_request *req); /* flag values */ #define SDHC_F_NOPWR0 (1 << 0) diff --git a/sdmmc.c b/sdmmc.c new file mode 100644 index 0000000..65ab436 --- /dev/null +++ b/sdmmc.c @@ -0,0 +1,258 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + SD/MMC interface + +Copyright (C) 2008, 2009 Sven Peter + +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, version 2. + +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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include "bsdtypes.h" +#include "sdhcreg.h" +#include "sdhcvar.h" +#include "sdmmcchip.h" +#include "sdmmcreg.h" +#include "sdmmcvar.h" +#include "sdmmc.h" +#include "gecko.h" +#include "string.h" +#include "utils.h" + +#define SDMMC_DEBUG 1 + +#ifdef SDMMC_DEBUG +static int sdmmcdebug = 5; +#define DPRINTF(n,s) do { if ((n) <= sdmmcdebug) gecko_printf s; } while (0) +#else +#define DPRINTF(n,s) do {} while(0) +#endif + +struct sdmmc_card { + struct sdmmc_chip_functions *functions; + sdmmc_chipset_handle_t handle; + char name[255]; + int no; + int inserted; + int sdhc_blockmode; +}; + +static struct sdmmc_card cards[SDHC_MAX_HOSTS]; +static int n_cards = 0; + +static inline int sdmmc_host_reset(struct sdmmc_card *card) +{ + return sdmmc_chip_host_reset(card->functions, card->handle); +} +static inline int sdmmc_host_card_detect(struct sdmmc_card *card) +{ + return sdmmc_chip_card_detect(card->functions, card->handle); +#if 0 +#define sdmmc_chip_host_maxblklen(tag, handle) \ + ((tag)->host_maxblklen((handle))) +#endif +} +static inline int sdmmc_host_ocr(struct sdmmc_card *card) +{ + return sdmmc_chip_host_ocr(card->functions, card->handle); +} +static inline int sdmmc_host_power(struct sdmmc_card *card, int ocr) +{ + return sdmmc_chip_bus_power(card->functions, card->handle, ocr); +} +static inline int sdmmc_host_clock(struct sdmmc_card *card, int freq) +{ + return sdmmc_chip_bus_clock(card->functions, card->handle, freq); +} +static inline void sdmmc_host_exec_command(struct sdmmc_card *card, struct + sdmmc_command *cmd) +{ + sdmmc_chip_exec_command(card->functions, card->handle, cmd); +} + +struct device *sdmmc_attach(struct sdmmc_chip_functions *functions, + sdmmc_chipset_handle_t handle, const char *name, int no) +{ + struct sdmmc_card *c; + + if (n_cards >= SDHC_MAX_HOSTS) { + gecko_printf("n_cards(%d) >= %d!\n", n_cards, SDHC_MAX_HOSTS); + gecko_printf("starlet is soo going to crash very soon...\n"); + + // HACK + return (struct device *)-1; + } + + c = &cards[n_cards++]; + memset(c, 0, sizeof(*c)); + + c->functions = functions; + c->handle = handle; + c->no = no; + strncpy(c->name, name, sizeof(c->name)); + + DPRINTF(0, ("sdmmc: attached new SD/MMC card %d for host [%s:%d]\n", + n_cards-1, c->name, c->no)); + + sdmmc_host_reset(c); + + if (sdmmc_host_card_detect(c)) { + DPRINTF(1, ("card is inserted. starting init sequence.\n")); + sdmmc_needs_discover((struct device *)(n_cards-1)); + } + + // HACK + return (struct device *)(n_cards-1); +} + +void sdmmc_needs_discover(struct device *dev) +{ + int no = (int)dev; + struct sdmmc_card *c = &cards[no]; + struct sdmmc_command cmd; + u32 ocr; + + DPRINTF(0, ("sdmmc: card %d needs discovery.\n", no)); + + if (!sdmmc_host_card_detect(c)) { + DPRINTF(1, ("sdmmc: card %d (no longer?) inserted.\n", no)); + c->inserted = 0; + return; + } + + DPRINTF(1, ("sdmmc: enabling power for %d\n", no)); + if (sdmmc_host_power(c, MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V) != 0) { + gecko_printf("sdmmc: powerup failed for card %d\n", no); + goto out; + } + + DPRINTF(1, ("sdmmc: enabling clock for %d\n", no)); + if (sdmmc_host_clock(c, SDMMC_DEFAULT_CLOCK) != 0) { + gecko_printf("sdmmc: could not enable clock for card %d\n", no); + goto out_power; + } + + DPRINTF(1, ("sdmmc: sending GO_IDLE_STATE for %d\n", no)); + + memset(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_GO_IDLE_STATE; + cmd.c_flags = SCF_RSP_R0; + sdmmc_host_exec_command(c, &cmd); + + if (cmd.c_error) { + gecko_printf("sdmmc: GO_IDLE_STATE failed with %d for card %d\n", + cmd.c_error, no); + goto out_clock; + } + DPRINTF(2, ("sdmmc: GO_IDLE_STATE response for %d: %x\n", no, + MMC_R1(cmd.c_resp))); + + DPRINTF(1, ("sdmmc: sending SEND_IF_COND for %d\n", no)); + + memset(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = SD_SEND_IF_COND; + cmd.c_arg = 0x1aa; + cmd.c_flags = SCF_RSP_R7; + sdmmc_host_exec_command(c, &cmd); + + gecko_printf("response: %08x %08x %08x %08x\n", cmd.c_resp[0], + cmd.c_resp[1], cmd.c_resp[2], cmd.c_resp[3]); + + ocr = sdmmc_host_ocr(c); + if (cmd.c_error || (cmd.c_resp[0] & 0xff) != 0xaa) + ocr &= ~SD_OCR_SDHC_CAP; + else + ocr |= SD_OCR_SDHC_CAP; + gecko_printf("-----> ocr: %x\n", ocr); + DPRINTF(2, ("sdmmc: SEND_IF_COND ocr: %x\n", ocr)); + + int tries; + for (tries = 10; tries > 0; tries--) { + udelay(10000); + + memset(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = MMC_APP_CMD; + cmd.c_arg = 0; + cmd.c_flags = SCF_RSP_R1; + sdmmc_host_exec_command(c, &cmd); + + if (cmd.c_error) + continue; + + memset(&cmd, 0, sizeof(cmd)); + cmd.c_opcode = SD_APP_OP_COND; + cmd.c_arg = ocr; + cmd.c_flags = SCF_RSP_R3; + sdmmc_host_exec_command(c, &cmd); + if (cmd.c_error) + continue; + + gecko_printf("response: %08x\n", cmd.c_resp[0]); + if (ISSET(cmd.c_resp[0], MMC_OCR_MEM_READY)) + break; + } + if (!ISSET(cmd.c_resp[0], MMC_OCR_MEM_READY)) { + gecko_printf("sdmmc: card %d failed to powerup.\n", no); + goto out_power; + } + + return; + +out_clock: +out_power: + sdmmc_host_power(c, 0); +out: + return; + +#if 0 +// struct sdmmc_task c_task; /* task queue entry */ + u_int16_t c_opcode; /* SD or MMC command index */ + u_int32_t c_arg; /* SD/MMC command argument */ + sdmmc_response c_resp; /* response buffer */ + void *c_data; /* buffer to send or read into */ + int c_datalen; /* length of data buffer */ + int c_blklen; /* block length */ + int c_flags; /* see below */ +#define SCF_ITSDONE 0x0001 /* command is complete */ +#define SCF_CMD(flags) ((flags) & 0x00f0) +#define SCF_CMD_AC 0x0000 +#define SCF_CMD_ADTC 0x0010 +#define SCF_CMD_BC 0x0020 +#define SCF_CMD_BCR 0x0030 +#define SCF_CMD_READ 0x0040 /* read command (data expected) */ +#define SCF_RSP_BSY 0x0100 +#define SCF_RSP_136 0x0200 +#define SCF_RSP_CRC 0x0400 +#define SCF_RSP_IDX 0x0800 +#define SCF_RSP_PRESENT 0x1000 +/* response types */ +#define SCF_RSP_R0 0 /* none */ +#define SCF_RSP_R1 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R1B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R2 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_136) +#define SCF_RSP_R3 (SCF_RSP_PRESENT) +#define SCF_RSP_R4 (SCF_RSP_PRESENT) +#define SCF_RSP_R5 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R5B (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX|SCF_RSP_BSY) +#define SCF_RSP_R6 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) +#define SCF_RSP_R7 (SCF_RSP_PRESENT|SCF_RSP_CRC|SCF_RSP_IDX) + int c_error; /* errno value on completion */ + + /* Host controller owned fields for data xfer in progress */ + int c_resid; /* remaining I/O */ + u_char *c_buf; /* remaining data */ +#endif +} + diff --git a/sdmmc.h b/sdmmc.h new file mode 100644 index 0000000..9ca8ec1 --- /dev/null +++ b/sdmmc.h @@ -0,0 +1,33 @@ +/* + mini - a Free Software replacement for the Nintendo/BroadOn IOS. + + SD/MMC interface + +Copyright (C) 2008, 2009 Sven Peter + +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, version 2. + +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, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef __SDMMC_H__ +#define __SDMMC_H__ 1 + +#include "sdmmcvar.h" +#include "sdmmcchip.h" + +#define SDMMC_DEFAULT_CLOCK 25000 + +struct device *sdmmc_attach(struct sdmmc_chip_functions *functions, + sdmmc_chipset_handle_t handle, const char *name, int no); +void sdmmc_needs_discover(struct device *dev); +#endif diff --git a/sdmmcchip.h b/sdmmcchip.h index 1846b1d..96f9fb0 100644 --- a/sdmmcchip.h +++ b/sdmmcchip.h @@ -81,8 +81,10 @@ struct sdmmcbus_attach_args { long max_xfer; }; +#if 0 void sdmmc_needs_discover(struct device *); void sdmmc_card_intr(struct device *); +#endif void sdmmc_delay(u_int); #endif diff --git a/sdmmcvar.h b/sdmmcvar.h index 0504860..5ab9e11 100644 --- a/sdmmcvar.h +++ b/sdmmcvar.h @@ -73,7 +73,7 @@ struct sdmmc_task { #define sdmmc_task_pending(xtask) ((xtask)->onqueue) struct sdmmc_command { - struct sdmmc_task c_task; /* task queue entry */ +// struct sdmmc_task c_task; /* task queue entry */ u_int16_t c_opcode; /* SD or MMC command index */ u_int32_t c_arg; /* SD/MMC command argument */ sdmmc_response c_resp; /* response buffer */