Last active
September 30, 2022 02:34
-
-
Save tsutsui/9939024 to your computer and use it in GitHub Desktop.
dumb driver for NetBSD/dreamcast SDMMC, based on NetBSD/evbsh3 https://twitter.com/tsutsuii/status/276275674245906432/photo/1 http://www.youtube.com/watch?v=v80kyFoSAx8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
? dreamcast/conf/SDMMC | |
? dreamcast/dev/scimci.c | |
Index: dreamcast/conf/files.dreamcast | |
=================================================================== | |
RCS file: /cvsroot/src/sys/arch/dreamcast/conf/files.dreamcast,v | |
retrieving revision 1.30 | |
diff -u -p -d -r1.30 files.dreamcast | |
--- dreamcast/conf/files.dreamcast 20 Feb 2008 21:43:33 -0000 1.30 | |
+++ dreamcast/conf/files.dreamcast 2 Apr 2014 10:37:00 -0000 | |
@@ -104,4 +104,12 @@ device aica: audiobus, auconv, mulaw | |
attach aica at g2bus | |
file arch/dreamcast/dev/g2/aica.c aica needs-flag | |
+# SD/MMC (requires hardware mod) | |
+include "dev/sdmmc/files.sdmmc" | |
+ | |
+# Serial Peripheral Interface for MMC/SD card via SCI port | |
+device scimci: sdmmcbus | |
+attach scimci at shb | |
+file arch/dreamcast/dev/scimci.c scimci | |
+ | |
include "arch/dreamcast/conf/majors.dreamcast" | |
Index: dreamcast/conf/majors.dreamcast | |
=================================================================== | |
RCS file: /cvsroot/src/sys/arch/dreamcast/conf/majors.dreamcast,v | |
retrieving revision 1.22 | |
diff -u -p -d -r1.22 majors.dreamcast | |
--- dreamcast/conf/majors.dreamcast 30 Jun 2011 20:09:22 -0000 1.22 | |
+++ dreamcast/conf/majors.dreamcast 2 Apr 2014 10:37:00 -0000 | |
@@ -55,6 +55,7 @@ device-major mmem char 62 block 21 mme | |
device-major mlcd char 63 mlcd | |
device-major ksyms char 64 ksyms | |
device-major wsfont char 65 wsfont | |
+device-major ld char 66 block 22 ld | |
device-major nsmb char 98 nsmb | |
Index: sh3/dev/scif.c | |
=================================================================== | |
RCS file: /cvsroot/src/sys/arch/sh3/dev/scif.c,v | |
retrieving revision 1.61 | |
diff -u -p -d -r1.61 scif.c | |
--- sh3/dev/scif.c 2 Feb 2012 19:43:00 -0000 1.61 | |
+++ sh3/dev/scif.c 2 Apr 2014 10:37:00 -0000 | |
@@ -614,9 +614,12 @@ scifparam(struct tty *tp, struct termios | |
* Set the flow control pins depending on the current flow control | |
* mode. | |
*/ | |
+#ifndef SCIF_DISABLE_HWFLOW | |
if (ISSET(t->c_cflag, CRTSCTS)) { | |
scif_fcr_write(scif_fcr_read() | SCFCR2_MCE); | |
- } else { | |
+ } else | |
+#endif | |
+ { | |
scif_fcr_write(scif_fcr_read() & ~SCFCR2_MCE); | |
} | |
Index: sh3/include/scireg.h | |
=================================================================== | |
RCS file: /cvsroot/src/sys/arch/sh3/include/scireg.h,v | |
retrieving revision 1.9 | |
diff -u -p -d -r1.9 scireg.h | |
--- sh3/include/scireg.h 30 Apr 2009 05:19:38 -0000 1.9 | |
+++ sh3/include/scireg.h 2 Apr 2014 10:37:00 -0000 | |
@@ -56,6 +56,7 @@ | |
#define SHREG_SCTDR (*(volatile unsigned char *) 0xffe0000c) | |
#define SHREG_SCSSR (*(volatile unsigned char *) 0xffe00010) | |
#define SHREG_SCRDR (*(volatile unsigned char *) 0xffe00014) | |
+#define SHREG_SCSCMR (*(volatile unsigned char *) 0xffe00018) | |
#define SHREG_SCSPTR (*(volatile unsigned char *) 0xffe0001c) | |
#endif | |
--- /dev/null 2014-04-02 10:35:36.000000000 +0000 | |
+++ dreamcast/conf/SDMMC 2012-12-11 13:08:36.000000000 +0000 | |
@@ -0,0 +1,260 @@ | |
+# $NetBSD: GENERIC,v 1.105.2.1 2012/07/20 23:07:58 riz Exp $ | |
+# | |
+# GENERIC machine description file | |
+# | |
+# This machine description file is used to generate the default NetBSD | |
+# kernel. The generic kernel does not include all options, subsystems | |
+# and device drivers, but should be useful for most applications. | |
+# | |
+# The machine description file can be customised for your specific | |
+# machine to reduce the kernel size and improve its performance. | |
+# | |
+# For further information on compiling NetBSD kernels, see the config(8) | |
+# man page. | |
+# | |
+# For further information on hardware support for this architecture, see | |
+# the intro(4) man page. For further information about kernel options | |
+# for this architecture, see the options(4) man page. For an explanation | |
+# of each device driver in this file see the section 4 man page for the | |
+# device. | |
+ | |
+include "arch/dreamcast/conf/std.dreamcast" | |
+ | |
+options INCLUDE_CONFIG_FILE # embed config file in kernel binary | |
+ | |
+maxusers 16 # estimated number of users | |
+ | |
+makeoptions COPTS="-O -fno-reorder-blocks" | |
+ | |
+# Standard system options | |
+#options INSECURE # disable kernel security levels | |
+ | |
+#options RTC_OFFSET=-540 | |
+options HZ=100 # clock interrupt generates every 1/HZ sec | |
+options NTP # NTP phase/frequency locked loop | |
+ | |
+options KTRACE # system call tracing via ktrace(1) | |
+ | |
+#options USERCONF # userconf(4) support | |
+#options PIPE_SOCKETPAIR # smaller, but slower pipe(2) | |
+options SYSCTL_INCLUDE_DESCR # Include sysctl descriptions in kernel | |
+ | |
+options SYSVMSG # System V-like message queues | |
+options SYSVSEM # System V-like semaphores | |
+options SYSVSHM # System V-like memory sharing | |
+options P1003_1B_SEMAPHORE # p1003.1b semaphore support | |
+ | |
+options MODULAR # new style module(7) framework | |
+ | |
+# Diagnostic/debugging support options | |
+options DIAGNOSTIC # cheap kernel consistency checks | |
+#options DEBUG # expensive debugging checks/support | |
+#options KMEMSTATS # kernel memory statistics (vmstat -m) | |
+options DDB # in-kernel debugger | |
+#options KGDB # remote debugger | |
+#options "KGDB_DEVNAME=\"scif\"",KGDB_DEVRATE=57600 | |
+#makeoptions DEBUG="-g" # compile full symbol table | |
+options SYMTAB_SPACE=340000 | |
+#options SYSCALL_DEBUG | |
+#options UVMHIST | |
+#options UVMHIST_PRINT | |
+ | |
+# Compatibility options | |
+#options COMPAT_16 # NetBSD 1.6, | |
+#options COMPAT_20 # NetBSD 2.0, | |
+#options COMPAT_30 # NetBSD 3.0, | |
+options COMPAT_40 # NetBSD 4.0 compatibility. | |
+options COMPAT_50 # NetBSD 5.0 compatibility. | |
+options COMPAT_43 # and 4.3BSD | |
+#options TCP_COMPAT_42 # 4.2BSD TCP/IP bug compat. Not recommended. | |
+options COMPAT_BSDPTY # /dev/[pt]ty?? ptys. | |
+ | |
+# Executable format options | |
+#options EXEC_COFF # COFF executables | |
+ | |
+# File systems | |
+file-system FFS # UFS | |
+#file-system EXT2FS # second extended file system (linux) | |
+#file-system LFS # log-structured file system | |
+file-system MFS # memory file system | |
+file-system NFS # Network File System client | |
+file-system CD9660 # CD-ROM file system | |
+file-system MSDOSFS # MS-DOS file system | |
+file-system FDESC # /dev/fd | |
+file-system KERNFS # /kern | |
+file-system PROCFS # /proc | |
+#file-system NULLFS # loopback file system | |
+#file-system OVERLAY # overlay file system | |
+#file-system UMAPFS # NULLFS + uid and gid remapping | |
+#file-system UNION # union file system | |
+file-system PTYFS # /dev/pts/N support | |
+#file-system TMPFS # Efficient memory file-system | |
+#file-system UDF # experimental - OSTA UDF CD/DVD file-system | |
+ | |
+# File system options | |
+#options QUOTA # legacy UFS quotas | |
+#options QUOTA2 # new, in-filesystem UFS quotas | |
+#options FFS_EI # FFS Endian Independent supoprt | |
+options WAPBL # File system journaling support | |
+#options UFS_DIRHASH # UFS Large Directory Hashing - Experimental | |
+#options NFSSERVER # Network File System server | |
+options FFS_NO_SNAPSHOT # No FFS snapshot support | |
+#options EXT2FS_SYSTEM_FLAGS # makes ext2fs file flags (append and | |
+ # immutable) behave as system flags. | |
+ | |
+# Networking options | |
+options INET # IP + ICMP + TCP + UDP | |
+options INET6 # IPV6 | |
+#options IPSEC # IP security | |
+#options IPSEC_ESP # IP security (encryption part; define w/IPSEC) | |
+#options IPSEC_NAT_T # IPsec NAT traversal (NAT-T) | |
+#options IPSEC_DEBUG # debug for IP security | |
+#options MROUTING # IP multicast routing | |
+#options PIM # Protocol Independent Multicast | |
+#options ISO,TPIP # OSI | |
+#options EON # OSI tunneling over IP | |
+#options NETATALK # AppleTalk networking protocols | |
+#options PPP_BSDCOMP # BSD-Compress compression support for PPP | |
+#options PPP_DEFLATE # Deflrate compression support for PPP | |
+#options PPP_FILTER # Active filter support for PPP (requires bpf) | |
+#options PFIL_HOOKS # pfil(9) packet filter hooks | |
+#options IPFILTER_LOG # ipmon(8) log support | |
+#options IPFILTER_LOOKUP # ippool(8) support | |
+#options IPFILTER_DEFAULT_BLOCK # block all packets by default | |
+#options TCP_DEBUG # Record last TCP_NDEBUG packets with SO_DEBUG | |
+ | |
+#options ALTQ # Manipulate network interfaces' output queues | |
+#options ALTQ_BLUE # Stochastic Fair Blue | |
+#options ALTQ_CBQ # Class-Based Queueing | |
+#options ALTQ_CDNR # Diffserv Traffic Conditioner | |
+#options ALTQ_FIFOQ # First-In First-Out Queue | |
+#options ALTQ_FLOWVALVE # RED/flow-valve (red-penalty-box) | |
+#options ALTQ_HFSC # Hierarchical Fair Service Curve | |
+#options ALTQ_LOCALQ # Local queueing discipline | |
+#options ALTQ_PRIQ # Priority Queueing | |
+#options ALTQ_RED # Random Early Detection | |
+#options ALTQ_RIO # RED with IN/OUT | |
+#options ALTQ_WFQ # Weighted Fair Queueing | |
+ | |
+#options PCIVERBOSE # verbose PCI device autoconfig messages | |
+#options MIIVERBOSE # verbose PHY autoconfig messages | |
+#options PCI_CONFIG_DUMP # verbosely dump PCI config space | |
+ | |
+options NFS_BOOT_DHCP # Support DHCP NFS root | |
+ | |
+options KLOADER # in-kernel bootloader | |
+#options KLOADER_DEBUG | |
+ | |
+# wscons options | |
+options WSEMUL_VT100 # VT100 / VT220 emulation | |
+options FONT_BOLD8x16 | |
+#options FONT_SONY8x16 | |
+ | |
+# Kernel root file system and dump configuration. | |
+#config netbsd root on ? type nfs | |
+#config netbsd root on wd0a type ffs | |
+config netbsd root on ? type ? | |
+ | |
+# | |
+# Device configuration | |
+# | |
+ | |
+mainbus0 at root | |
+ | |
+cpu* at mainbus? | |
+shb* at mainbus? | |
+ | |
+# Serial Devices | |
+#options SCIFCONSOLE | |
+options SCIFCN_SPEED=57600 | |
+options SCIF_DISABLE_HWFLOW | |
+scif0 at shb? | |
+ | |
+# Serial Pheripheral Interface via SCI for MMC | |
+scimci0 at shb? | |
+sdmmc* at scimci? | |
+#options SCIMCI_DEBUG | |
+#options SDMMC_DEBUG | |
+#options SDMMC_DUMP_CSD | |
+ld* at sdmmc? # MMC card | |
+ | |
+pvr0 at shb? | |
+wsdisplay* at pvr? console ? | |
+ | |
+maple0 at shb? | |
+ | |
+mkbd* at maple? port ? subunit ? | |
+wskbd* at mkbd? mux 1 console ? | |
+ | |
+mms* at maple? port ? subunit ? | |
+wsmouse* at mms? mux 0 | |
+ | |
+mmem* at maple? port ? subunit ? | |
+mlcd* at maple? port ? subunit ? | |
+ | |
+gdrom0 at shb? | |
+ | |
+g2bus0 at shb? | |
+g2rtc0 at g2bus? # time-of-day clock | |
+gapspci* at g2bus? # GAPS PCI bridge | |
+pci* at gapspci? | |
+rtk* at pci? dev ? function ? # SEGA Broadband Adapter | |
+rlphy* at mii? phy ? | |
+ | |
+#mbe* at g2bus? # SEGA LAN Adapter | |
+ | |
+#aica* at g2bus? # AICA Sound Processing Unit | |
+#audio* at aica? | |
+ | |
+#pseudo-device cgd 2 # cryptographic disk devices | |
+pseudo-device md # memory disk device (ramdisk) | |
+#pseudo-device vnd # disk-like interface to files | |
+#options VND_COMPRESSION # compressed vnd(4) | |
+ | |
+# network pseudo-devices | |
+pseudo-device bpfilter # Berkeley packet filter | |
+#pseudo-device carp # Common Address Redundancy Protocol | |
+#pseudo-device ipfilter # IP filter (firewall) and NAT | |
+pseudo-device loop # network loopback | |
+#pseudo-device ppp # Point-to-Point Protocol | |
+#pseudo-device pppoe # PPP over Ethernet (RFC 2516) | |
+#pseudo-device sl # Serial Line IP | |
+#pseudo-device tun # network tunneling over tty | |
+#pseudo-device tap # virtual Ethernet | |
+#pseudo-device gre # generic L3 over IP tunnel | |
+#pseudo-device gif # IPv[46] over IPv[46] tunnel (RFC1933) | |
+#pseudo-device faith # IPv[46] tcp relay translation i/f | |
+#pseudo-device stf # 6to4 IPv6 over IPv4 encapsulation | |
+#pseudo-device vlan # IEEE 802.1q encapsulation | |
+#pseudo-device bridge # simple inter-network bridging | |
+#options BRIDGE_IPF # bridge uses IP/IPv6 pfil hooks too | |
+#pseudo-device agr # IEEE 802.3ad link aggregation | |
+ | |
+# | |
+# accept filters | |
+#pseudo-device accf_data # "dataready" accept filter | |
+#pseudo-device accf_http # "httpready" accept filter | |
+ | |
+# miscellaneous pseudo-devices | |
+pseudo-device pty # pseudo-terminals | |
+#pseudo-device clockctl # user control of clock subsystem | |
+pseudo-device wsmux # mouse & keyboard multiplexor | |
+pseudo-device ksyms # /dev/ksyms | |
+#pseudo-device pf # PF packet filter | |
+#pseudo-device pflog # PF log if | |
+ | |
+# Veriexec | |
+# | |
+# a pseudo device needed for veriexec | |
+#pseudo-device veriexec 1 | |
+# | |
+# Uncomment the fingerprint methods below that are desired. Note that | |
+# removing fingerprint methods will have almost no impact on the kernel | |
+# code size. | |
+# | |
+#options VERIFIED_EXEC_FP_RMD160 | |
+#options VERIFIED_EXEC_FP_SHA256 | |
+#options VERIFIED_EXEC_FP_SHA384 | |
+#options VERIFIED_EXEC_FP_SHA512 | |
+#options VERIFIED_EXEC_FP_SHA1 | |
+#options VERIFIED_EXEC_FP_MD5 | |
--- /dev/null 2014-04-02 10:35:36.000000000 +0000 | |
+++ dreamcast/dev/scimci.c 2012-12-16 09:51:47.000000000 +0000 | |
@@ -0,0 +1,665 @@ | |
+/* $NetBSD$ */ | |
+ | |
+/*- | |
+ * Copyright (C) 2009 NONAKA Kimihiro <nonaka@netbsd.org> | |
+ * All rights reserved. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | |
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | |
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
+ */ | |
+ | |
+/* | |
+ * Serial Peripheral interface driver to access MMC card | |
+ */ | |
+ | |
+#include "opt_pclock.h" | |
+ | |
+#include <sys/cdefs.h> | |
+__KERNEL_RCSID(0, "$NetBSD$"); | |
+ | |
+#include <sys/param.h> | |
+#include <sys/device.h> | |
+#include <sys/systm.h> | |
+#include <sys/malloc.h> | |
+#include <sys/kernel.h> | |
+#include <sys/proc.h> | |
+#include <sys/bus.h> | |
+#include <sys/intr.h> | |
+ | |
+#include <sh3/devreg.h> | |
+#include <sh3/pfcreg.h> | |
+#include <sh3/scireg.h> | |
+#include <sh3/clock.h> | |
+#include <sh3/scifreg.h> | |
+#include <sh3/cpgreg.h> | |
+ | |
+#include <dev/sdmmc/sdmmcvar.h> | |
+#include <dev/sdmmc/sdmmcchip.h> | |
+#include <dev/cons.h> | |
+ | |
+#ifdef SCIMCI_DEBUG | |
+int scimci_debug = 1; | |
+#define DPRINTF(n,s) do { if ((n) <= scimci_debug) printf s; } while (0) | |
+#else | |
+#define DPRINTF(n,s) do {} while (0) | |
+#endif | |
+ | |
+static int scimci_host_reset(sdmmc_chipset_handle_t); | |
+static uint32_t scimci_host_ocr(sdmmc_chipset_handle_t); | |
+static int scimci_host_maxblklen(sdmmc_chipset_handle_t); | |
+static int scimci_card_detect(sdmmc_chipset_handle_t); | |
+static int scimci_write_protect(sdmmc_chipset_handle_t); | |
+static int scimci_bus_power(sdmmc_chipset_handle_t, uint32_t); | |
+static int scimci_bus_clock(sdmmc_chipset_handle_t, int); | |
+static int scimci_bus_width(sdmmc_chipset_handle_t, int); | |
+static void scimci_exec_command(sdmmc_chipset_handle_t, | |
+ struct sdmmc_command *); | |
+ | |
+static struct sdmmc_chip_functions scimci_chip_functions = { | |
+ /* host controller reset */ | |
+ .host_reset = scimci_host_reset, | |
+ | |
+ /* host controller capabilities */ | |
+ .host_ocr = scimci_host_ocr, | |
+ .host_maxblklen = scimci_host_maxblklen, | |
+ | |
+ /* card detection */ | |
+ .card_detect = scimci_card_detect, | |
+ | |
+ /* write protect */ | |
+ .write_protect = scimci_write_protect, | |
+ | |
+ /* bus power, clock frequency, width */ | |
+ .bus_power = scimci_bus_power, | |
+ .bus_clock = scimci_bus_clock, | |
+ .bus_width = scimci_bus_width, | |
+ | |
+ /* command execution */ | |
+ .exec_command = scimci_exec_command, | |
+ | |
+ /* card interrupt */ | |
+ .card_enable_intr = NULL, | |
+ .card_intr_ack = NULL, | |
+}; | |
+ | |
+static void scimci_spi_initialize(sdmmc_chipset_handle_t); | |
+ | |
+static struct sdmmc_spi_chip_functions scimci_spi_chip_functions = { | |
+ .initialize = scimci_spi_initialize, | |
+}; | |
+ | |
+#define CSR_SET_1(reg,set,mask) \ | |
+do { \ | |
+ uint8_t _r; \ | |
+ _r = _reg_read_1((reg)); \ | |
+ _r &= ~(mask); \ | |
+ _r |= (set); \ | |
+ _reg_write_1((reg), _r); \ | |
+} while (/*CONSTCOND*/0) | |
+ | |
+#define CSR_SET_2(reg,set,mask) \ | |
+do { \ | |
+ uint16_t _r; \ | |
+ _r = _reg_read_2((reg)); \ | |
+ _r &= ~(mask); \ | |
+ _r |= (set); \ | |
+ _reg_write_2((reg), _r); \ | |
+} while (/*CONSTCOND*/0) | |
+ | |
+#define CSR_CLR_1(reg,clr) \ | |
+do { \ | |
+ uint8_t _r; \ | |
+ _r = _reg_read_1((reg)); \ | |
+ _r &= ~(clr); \ | |
+ _reg_write_1((reg), _r); \ | |
+} while (/*CONSTCOND*/0) | |
+ | |
+#define CSR_CLR_2(reg,clr) \ | |
+do { \ | |
+ uint16_t _r; \ | |
+ _r = _reg_read_2((reg)); \ | |
+ _r &= ~(clr); \ | |
+ _reg_write_2((reg), _r); \ | |
+} while (/*CONSTCOND*/0) | |
+ | |
+#define SCSPTR_EIO 0x80 | |
+ | |
+/* SCSCR */ | |
+#define SCSCR_SCK_OUT 0 | |
+#define SCSCR_SCK_IN (SCSCR_CKE1) | |
+ | |
+#define LOW_CLOCK (400 * 1000) | |
+#define MID_CLOCK (500 * 1000) | |
+ | |
+#define LOW_SPEED ((PCLOCK / ((8 / 2) * LOW_CLOCK)) - 1) | |
+#define MID_SPEED ((PCLOCK / ((8 / 2) * MID_CLOCK)) - 1) | |
+#define MMC_TIME_OVER 1000 | |
+ | |
+struct scimci_softc { | |
+ device_t sc_dev; | |
+ device_t sc_sdmmc; | |
+}; | |
+ | |
+static int scimci_match(device_t, cfdata_t, void *); | |
+static void scimci_attach(device_t, device_t, void *); | |
+ | |
+CFATTACH_DECL_NEW(scimci, sizeof(struct scimci_softc), | |
+ scimci_match, scimci_attach, NULL, NULL); | |
+ | |
+static void scimci_putc(int); | |
+static void scimci_putc_sw(void); | |
+static int scimci_getc(void); | |
+static void scimci_getc_sw(void); | |
+static void scimci_cmd_cfgread(struct scimci_softc *, struct sdmmc_command *); | |
+static void scimci_cmd_read(struct scimci_softc *, struct sdmmc_command *); | |
+static void scimci_cmd_write(struct scimci_softc *, struct sdmmc_command *); | |
+ | |
+void scimci_read_buffer(u_char *buf); | |
+void scimci_write_buffer(const u_char *buf); | |
+ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_match(device_t parent, cfdata_t cf, void *aux) | |
+{ | |
+ | |
+ /* XXX */ | |
+ return 1; | |
+} | |
+ | |
+/*ARGSUSED*/ | |
+static void | |
+scimci_attach(device_t parent, device_t self, void *aux) | |
+{ | |
+ struct scimci_softc *sc = device_private(self); | |
+ struct sdmmcbus_attach_args saa; | |
+ | |
+ sc->sc_dev = self; | |
+ | |
+ aprint_naive("\n"); | |
+ aprint_normal(": SCI MMC controller\n"); | |
+ | |
+ /* clear MSTP0 in STBCR (disabled by firmware?) to activate SCI */; | |
+ *(volatile uint8_t *)SH4_STBCR &= ~0x01; | |
+ | |
+ /* Setup */ | |
+ | |
+ /* RTS is connected to /CS */ | |
+ SHREG_SCSPTR2 = SCSPTR2_RTSIO | SCSPTR2_RTSDT; | |
+ | |
+ /* Clear SCSPTR_SPB1IO and SCSPTR_SPB0IO (disable I/O and use SCI) */ | |
+ SHREG_SCSPTR = SCSPTR_SPB1DT | SCSPTR_SPB0DT; | |
+ | |
+ SHREG_SCSCR = 0x00; | |
+ SHREG_SCSSR = 0x00; | |
+ SHREG_SCSCMR = 0x08; /* set SDIR (MSB first) */ | |
+#if 0 | |
+ SHREG_SCSMR = 0; | |
+ SHREG_SCSPTR = 0x0f; | |
+ printf("%s: SCSPTR = %02x\n", __func__, SHREG_SCSPTR); | |
+ while (cngetc() == ' ') { | |
+ SHREG_SCSPTR = 0x0e; | |
+ printf("%s: SCSPTR = %02x\n", __func__, SHREG_SCSPTR); | |
+ (void)cngetc(); | |
+ SHREG_SCSPTR = 0x0b; | |
+ printf("%s: SCSPTR = %02x\n", __func__, SHREG_SCSPTR); | |
+ (void)cngetc(); | |
+ SHREG_SCSPTR = 0x0f; | |
+ printf("%s: SCSPTR = %02x\n", __func__, SHREG_SCSPTR); | |
+ } | |
+#endif | |
+ SHREG_SCSMR = SCSMR_CA; /* clock sync mode */ | |
+ SHREG_SCBRR = LOW_SPEED; | |
+ delay(1000); /* wait at least 1 bit time */ | |
+ | |
+ /* | |
+ * Attach the generic SD/MMC bus driver. (The bus driver must | |
+ * not invoke any chipset functions before it is attached.) | |
+ */ | |
+ memset(&saa, 0, sizeof(saa)); | |
+ saa.saa_busname = "sdmmc"; | |
+ saa.saa_sct = &scimci_chip_functions; | |
+ saa.saa_spi_sct = &scimci_spi_chip_functions; | |
+ saa.saa_sch = sc; | |
+ saa.saa_clkmin = (PCLOCK / 1000) / ((LOW_SPEED + 1) * 4); | |
+ saa.saa_clkmax = (PCLOCK / 1000) / ((MID_SPEED + 1) * 4); | |
+ saa.saa_caps = SMC_CAPS_SPI_MODE | |
+ | SMC_CAPS_SINGLE_ONLY | |
+ | SMC_CAPS_POLL_CARD_DET; | |
+ | |
+ sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL); | |
+ if (sc->sc_sdmmc == NULL) | |
+ aprint_error_dev(sc->sc_dev, "couldn't attach bus\n"); | |
+} | |
+ | |
+/* | |
+ * SCI access functions | |
+ */ | |
+static void | |
+scimci_putc(int c) | |
+{ | |
+ | |
+ SHREG_SCSCR = SCSCR_TE | SCSCR_SCK_OUT; | |
+ while ((SHREG_SCSSR & SCSSR_TDRE) == 0) | |
+ continue; | |
+ SHREG_SCTDR = (uint8_t)c; | |
+ (void) SHREG_SCSSR; | |
+ SHREG_SCSSR = 0; | |
+} | |
+ | |
+static void | |
+scimci_putc_sw(void) | |
+{ | |
+ | |
+ while ((SHREG_SCSSR & SCSSR_TEND) == 0) | |
+ continue; | |
+ | |
+ SHREG_SCSCR |= SCSCR_SCK_IN; | |
+ SHREG_SCSMR = 0; | |
+ SHREG_SCSCR = SCSCR_SCK_OUT; | |
+ SHREG_SCSSR = 0; | |
+ SHREG_SCSMR = SCSMR_CA; | |
+} | |
+ | |
+static int | |
+scimci_getc(void) | |
+{ | |
+ int c; | |
+ | |
+ SHREG_SCSCR = SCSCR_RE | SCSCR_SCK_OUT; | |
+ if (SHREG_SCSSR & SCSSR_ORER) { | |
+ SHREG_SCSSR &= ~SCSSR_ORER; | |
+ return -1; | |
+ } | |
+ while ((SHREG_SCSSR & SCSSR_RDRF) == 0) | |
+ continue; | |
+ c = SHREG_SCRDR; | |
+ (void) SHREG_SCSSR; | |
+ SHREG_SCSSR = 0; | |
+ | |
+ return c; | |
+} | |
+ | |
+static void | |
+scimci_getc_sw(void) | |
+{ | |
+ | |
+ SHREG_SCBRR = LOW_SPEED; | |
+ while ((SHREG_SCSSR & SCSSR_RDRF) == 0) | |
+ continue; | |
+ (void) SHREG_SCRDR; | |
+ | |
+ SHREG_SCSCR |= SCSCR_SCK_IN; | |
+ SHREG_SCSMR = 0; | |
+ SHREG_SCSCR = SCSCR_SCK_OUT; | |
+ SHREG_SCSSR = 0; | |
+ SHREG_SCSMR = SCSMR_CA; | |
+} | |
+ | |
+/* | |
+ * Reset the host controller. Called during initialization, when | |
+ * cards are removed, upon resume, and during error recovery. | |
+ */ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_host_reset(sdmmc_chipset_handle_t sch) | |
+{ | |
+ | |
+ return 0; | |
+} | |
+ | |
+/*ARGSUSED*/ | |
+static uint32_t | |
+scimci_host_ocr(sdmmc_chipset_handle_t sch) | |
+{ | |
+ | |
+ return MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V; | |
+} | |
+ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_host_maxblklen(sdmmc_chipset_handle_t sch) | |
+{ | |
+ | |
+ return 512; | |
+} | |
+ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_card_detect(sdmmc_chipset_handle_t sch) | |
+{ | |
+ uint8_t reg; | |
+ int s; | |
+ | |
+ s = splhigh(); | |
+ /* assume /CD is connected to CTS at SCIF */ | |
+ reg = SHREG_SCSPTR2; | |
+ splx(s); | |
+ | |
+ return (reg & SCSPTR2_CTSDT) ? 0 : 1; | |
+} | |
+ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_write_protect(sdmmc_chipset_handle_t sch) | |
+{ | |
+ | |
+ return 0; /* no write protect signal */ | |
+} | |
+ | |
+/* | |
+ * Set or change SD bus voltage and enable or disable SD bus power. | |
+ * Return zero on success. | |
+ */ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) | |
+{ | |
+ | |
+ if ((ocr & (MMC_OCR_3_2V_3_3V|MMC_OCR_3_3V_3_4V)) == 0) | |
+ return 1; | |
+ | |
+ /*XXX???*/ | |
+ return 0; | |
+} | |
+ | |
+/* | |
+ * Set or change MMCLK frequency or disable the MMC clock. | |
+ * Return zero on success. | |
+ */ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_bus_clock(sdmmc_chipset_handle_t sch, int freq) | |
+{ | |
+ | |
+ return 0; | |
+} | |
+ | |
+/*ARGSUSED*/ | |
+static int | |
+scimci_bus_width(sdmmc_chipset_handle_t sch, int width) | |
+{ | |
+ | |
+ if (width != 1) | |
+ return 1; | |
+ return 0; | |
+} | |
+ | |
+/*ARGSUSED*/ | |
+static void | |
+scimci_spi_initialize(sdmmc_chipset_handle_t sch) | |
+{ | |
+ int i, s; | |
+ | |
+ s = splhigh(); | |
+ /* make sure to negate /CS, connected to RTS at SCIF */ | |
+ SHREG_SCSPTR2 = SCSPTR2_RTSIO | SCSPTR2_RTSDT; | |
+ for (i = 0; i < 20; i++) | |
+ scimci_putc(0xff); | |
+ scimci_putc_sw(); | |
+ splx(s); | |
+} | |
+ | |
+static void | |
+scimci_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) | |
+{ | |
+ struct scimci_softc *sc = (struct scimci_softc *)sch; | |
+ uint16_t resp; | |
+ int timo; | |
+ int s; | |
+ | |
+ DPRINTF(1,("%s: start cmd %d arg=%#x data=%p dlen=%d flags=%#x " | |
+ "proc=%p \"%s\"\n", device_xname(sc->sc_dev), | |
+ cmd->c_opcode, cmd->c_arg, cmd->c_data, cmd->c_datalen, | |
+ cmd->c_flags, curproc, curproc ? curproc->p_comm : "")); | |
+ | |
+ s = splhigh(); | |
+ /* assert /CS, connected to RTS at SCIF */ | |
+ SHREG_SCSPTR2 = SCSPTR2_RTSIO; | |
+ delay(10); | |
+ | |
+ if (cmd->c_opcode == MMC_GO_IDLE_STATE) | |
+ SHREG_SCBRR = LOW_SPEED; | |
+ else | |
+ SHREG_SCBRR = MID_SPEED; | |
+ | |
+ scimci_putc(0xff); | |
+ scimci_putc(0x40 | (cmd->c_opcode & 0x3f)); | |
+ scimci_putc((cmd->c_arg >> 24) & 0xff); | |
+ scimci_putc((cmd->c_arg >> 16) & 0xff); | |
+ scimci_putc((cmd->c_arg >> 8) & 0xff); | |
+ scimci_putc((cmd->c_arg >> 0) & 0xff); | |
+ scimci_putc((cmd->c_opcode == MMC_GO_IDLE_STATE) ? 0x95 : | |
+ (cmd->c_opcode == SD_SEND_IF_COND) ? 0x87 : 0); /* CRC */ | |
+ scimci_putc(0xff); | |
+ scimci_putc_sw(); | |
+ | |
+ timo = MMC_TIME_OVER; | |
+ while ((resp = scimci_getc()) & 0x80) { | |
+ if (--timo == 0) { | |
+ DPRINTF(1, ("%s: response timeout (resp=%02x)\n", | |
+ device_xname(sc->sc_dev), resp)); | |
+ scimci_getc_sw(); | |
+ cmd->c_error = ETIMEDOUT; | |
+ goto out; | |
+ } | |
+ } | |
+ if (ISSET(cmd->c_flags, SCF_RSP_SPI_S2)) { | |
+ resp |= (uint16_t)scimci_getc() << 8; | |
+ } else if (ISSET(cmd->c_flags, SCF_RSP_SPI_B4)) { | |
+ cmd->c_resp[1] = (uint32_t) scimci_getc() << 24; | |
+ cmd->c_resp[1] |= (uint32_t) scimci_getc() << 16; | |
+ cmd->c_resp[1] |= (uint32_t) scimci_getc() << 8; | |
+ cmd->c_resp[1] |= (uint32_t) scimci_getc(); | |
+ DPRINTF(1, ("R3 resp: %#x\n", cmd->c_resp[1])); | |
+ } | |
+ scimci_getc_sw(); | |
+ | |
+ cmd->c_resp[0] = resp; | |
+ if (resp != 0 && resp != R1_SPI_IDLE) { | |
+ DPRINTF(1, ("%s: response error: %#x\n", | |
+ device_xname(sc->sc_dev), resp)); | |
+ cmd->c_error = EIO; | |
+ goto out; | |
+ } | |
+ DPRINTF(1, ("R1 resp: %#x\n", resp)); | |
+ | |
+ if (cmd->c_datalen > 0) { | |
+ if (ISSET(cmd->c_flags, SCF_CMD_READ)) { | |
+ /* XXX: swap in this place? */ | |
+ if (cmd->c_opcode == MMC_SEND_CID || | |
+ cmd->c_opcode == MMC_SEND_CSD) { | |
+ sdmmc_response res; | |
+ uint32_t *p = cmd->c_data; | |
+ | |
+ scimci_cmd_cfgread(sc, cmd); | |
+ res[0] = be32toh(p[3]); | |
+ res[1] = be32toh(p[2]); | |
+ res[2] = be32toh(p[1]); | |
+ res[3] = be32toh(p[0]); | |
+ memcpy(p, &res, sizeof(res)); | |
+ } else { | |
+ scimci_cmd_read(sc, cmd); | |
+ } | |
+ } else { | |
+ scimci_cmd_write(sc, cmd); | |
+ } | |
+ } | |
+ | |
+out: | |
+ /* negate /CS */ | |
+ SHREG_SCSPTR2 = SCSPTR2_RTSIO | SCSPTR2_RTSDT; | |
+ splx(s); | |
+ SET(cmd->c_flags, SCF_ITSDONE); | |
+ | |
+ DPRINTF(1,("%s: cmd %d done (flags=%#x error=%d)\n", | |
+ device_xname(sc->sc_dev), cmd->c_opcode, | |
+ cmd->c_flags, cmd->c_error)); | |
+} | |
+ | |
+static void | |
+scimci_cmd_cfgread(struct scimci_softc *sc, struct sdmmc_command *cmd) | |
+{ | |
+ u_char *data = cmd->c_data; | |
+ int timo; | |
+ int c; | |
+ int i; | |
+ | |
+ /* wait data token */ | |
+ for (timo = MMC_TIME_OVER; timo > 0; timo--) { | |
+ c = scimci_getc(); | |
+ if (c < 0) { | |
+ aprint_error_dev(sc->sc_dev, "cfg read i/o error\n"); | |
+ cmd->c_error = EIO; | |
+ return; | |
+ } | |
+ if (c != 0xff) | |
+ break; | |
+ } | |
+ if (timo == 0) { | |
+ aprint_error_dev(sc->sc_dev, "cfg read timeout\n"); | |
+ cmd->c_error = ETIMEDOUT; | |
+ return; | |
+ } | |
+ if (c != 0xfe) { | |
+ aprint_error_dev(sc->sc_dev, "cfg read error (data=%#x)\n", c); | |
+ cmd->c_error = EIO; | |
+ return; | |
+ } | |
+ | |
+ /* data read */ | |
+ SHREG_SCSCR = SCSCR_RE | SCSCR_SCK_OUT; | |
+ data[0] = '\0'; /* XXXFIXME!!! */ | |
+ for (i = 1 /* XXXFIXME!!!*/ ; i < cmd->c_datalen; i++) { | |
+ while ((SHREG_SCSSR & SCSSR_RDRF) == 0) | |
+ continue; | |
+ data[i] = SHREG_SCRDR; | |
+ (void) SHREG_SCSSR; | |
+ SHREG_SCSSR = 0; | |
+ } | |
+ | |
+ SHREG_SCBRR = LOW_SPEED; | |
+ (void) scimci_getc(); | |
+ (void) scimci_getc(); | |
+ (void) scimci_getc(); | |
+ scimci_getc_sw(); | |
+ | |
+#ifdef SCIMCI_DEBUG | |
+ sdmmc_dump_data(NULL, cmd->c_data, cmd->c_datalen); | |
+#endif | |
+} | |
+ | |
+static void | |
+scimci_cmd_read(struct scimci_softc *sc, struct sdmmc_command *cmd) | |
+{ | |
+ u_char *data = cmd->c_data; | |
+ int timo; | |
+ int c; | |
+ int i; | |
+ | |
+ /* wait data token */ | |
+ for (timo = MMC_TIME_OVER; timo > 0; timo--) { | |
+ c = scimci_getc(); | |
+ if (c < 0) { | |
+ aprint_error_dev(sc->sc_dev, "read i/o error\n"); | |
+ cmd->c_error = EIO; | |
+ return; | |
+ } | |
+ if (c != 0xff) | |
+ break; | |
+ } | |
+ if (timo == 0) { | |
+ aprint_error_dev(sc->sc_dev, "read timeout\n"); | |
+ cmd->c_error = ETIMEDOUT; | |
+ return; | |
+ } | |
+ if (c != 0xfe) { | |
+ aprint_error_dev(sc->sc_dev, "read error (data=%#x)\n", c); | |
+ cmd->c_error = EIO; | |
+ return; | |
+ } | |
+ | |
+ /* data read */ | |
+ SHREG_SCBRR = MID_SPEED; | |
+ SHREG_SCSCR = SCSCR_RE | SCSCR_SCK_OUT; | |
+ for (i = 0; i < cmd->c_datalen; i++) { | |
+ while ((SHREG_SCSSR & SCSSR_RDRF) == 0) | |
+ continue; | |
+ data[i] = SHREG_SCRDR; | |
+ (void) SHREG_SCSSR; | |
+ SHREG_SCSSR = 0; | |
+ } | |
+ | |
+ SHREG_SCBRR = LOW_SPEED; | |
+ (void) scimci_getc(); | |
+ (void) scimci_getc(); | |
+ (void) scimci_getc(); | |
+ scimci_getc_sw(); | |
+ | |
+#ifdef SCIMCI_DEBUG | |
+ sdmmc_dump_data(NULL, cmd->c_data, cmd->c_datalen); | |
+#endif | |
+} | |
+ | |
+static void | |
+scimci_cmd_write(struct scimci_softc *sc, struct sdmmc_command *cmd) | |
+{ | |
+ char *data = cmd->c_data; | |
+ int timo; | |
+ int c; | |
+ int i; | |
+ | |
+ scimci_putc(0xff); | |
+ scimci_putc(0xfe); | |
+ | |
+ /* data write */ | |
+ SHREG_SCBRR = MID_SPEED; | |
+ SHREG_SCSCR = SCSCR_TE | SCSCR_SCK_OUT; | |
+ for (i = 0; i < cmd->c_datalen; i++) { | |
+ while ((SHREG_SCSSR & SCSSR_TDRE) == 0) | |
+ continue; | |
+ SHREG_SCTDR = data[i]; | |
+ (void) SHREG_SCSSR; | |
+ SHREG_SCSSR = 0; | |
+ } | |
+ | |
+ SHREG_SCBRR = LOW_SPEED; | |
+ scimci_putc(0); | |
+ scimci_putc(0); | |
+ scimci_putc(0); | |
+ scimci_putc_sw(); | |
+ | |
+ for (timo = MMC_TIME_OVER * 1000; timo > 0; timo--) { | |
+ c = scimci_getc(); | |
+ if (c < 0) { | |
+ aprint_error_dev(sc->sc_dev, "write i/o error\n"); | |
+ cmd->c_error = EIO; | |
+ scimci_getc_sw(); | |
+ return; | |
+ } | |
+ if (c == 0xff) | |
+ break; | |
+ delay(1); | |
+ } | |
+ if (timo == 0) { | |
+ aprint_error_dev(sc->sc_dev, "write timeout\n"); | |
+ cmd->c_error = ETIMEDOUT; | |
+ } | |
+ scimci_getc_sw(); | |
+} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment