Module Name:    src
Committed By:   jdc
Date:           Wed Aug  8 06:19:00 UTC 2012

Modified Files:
        src/sys/dev/sdmmc [netbsd-6]: sdhc.c sdhcreg.h sdmmc_mem.c sdmmcreg.h

Log Message:
Pull up revisions:
  src/sys/dev/sdmmc/sdhc.c revisions 1.16,1.20,1.21,1.22,1.23 via patch,1.25
  src/sys/dev/sdmmc/sdhcreg.h revision 1.8
  src/sys/dev/sdmmc/sdmmc_mem.c revisions 1.21,1.22
  src/sys/dev/sdmmc/sdmmcreg.h revisions 1.10,1.11,1.12
(requested by matt in ticket 441).

SDHCI byte swaps the BE response on the wire into LE registers.
As we always want response data in LE, use bus_space_read_stream.
Additonally, read response data in 1 or 4 4-byte chunks, instead of
one 4-byte chunk or 15 1-byte chunks.

bus_space_*_stream_N() functions are not universally available.
Provite alternate implementation for when they are unavailable.

Handle interrupt acknowledgement in the SDHC_FLAG_32BIT_ACCESS case in
the same way as non-SDHC_FLAG_32BIT_ACCESS case.

If there was an error in 32-bit mode, just set ERROR_INTERRUPT otherwise
see if matched anything we care about.

Add use of watermark register when PIO to an ESDHC.  After every kill or
drain of watermask words, pause a bit to give time for the fifo to recover.
Always the command response in BE byteorder.  Rewrite __bitfield to deal
with this.

Responses are actually in host order (except SCR which is return in
big endian so that's convert to host order).

Fix comments about __bitfield.


To generate a diff of this commit:
cvs rdiff -u -r1.10.2.1 -r1.10.2.2 src/sys/dev/sdmmc/sdhc.c
cvs rdiff -u -r1.5 -r1.5.2.1 src/sys/dev/sdmmc/sdhcreg.h
cvs rdiff -u -r1.20 -r1.20.2.1 src/sys/dev/sdmmc/sdmmc_mem.c
cvs rdiff -u -r1.8 -r1.8.2.1 src/sys/dev/sdmmc/sdmmcreg.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/sdhc.c
diff -u src/sys/dev/sdmmc/sdhc.c:1.10.2.1 src/sys/dev/sdmmc/sdhc.c:1.10.2.2
--- src/sys/dev/sdmmc/sdhc.c:1.10.2.1	Mon Jun 11 17:45:32 2012
+++ src/sys/dev/sdmmc/sdhc.c	Wed Aug  8 06:18:59 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhc.c,v 1.10.2.1 2012/06/11 17:45:32 riz Exp $	*/
+/*	$NetBSD: sdhc.c,v 1.10.2.2 2012/08/08 06:18:59 jdc Exp $	*/
 /*	$OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $	*/
 
 /*
@@ -23,7 +23,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.10.2.1 2012/06/11 17:45:32 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.10.2.2 2012/08/08 06:18:59 jdc Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -987,14 +987,11 @@ sdhc_exec_command(sdmmc_chipset_handle_t
 	 */
 	mutex_enter(&hp->host_mtx);
 	if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
+		cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE + 0);
 		if (ISSET(cmd->c_flags, SCF_RSP_136)) {
-			uint8_t *p = (uint8_t *)cmd->c_resp;
-			int i;
-
-			for (i = 0; i < 15; i++)
-				*p++ = HREAD1(hp, SDHC_RESPONSE + i);
-		} else {
-			cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE);
+			cmd->c_resp[1] = HREAD4(hp, SDHC_RESPONSE + 4);
+			cmd->c_resp[2] = HREAD4(hp, SDHC_RESPONSE + 8);
+			cmd->c_resp[3] = HREAD4(hp, SDHC_RESPONSE + 12);
 		}
 	}
 	mutex_exit(&hp->host_mtx);
@@ -1379,17 +1376,33 @@ static void
 esdhc_read_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
 {
 	uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
+	uint32_t v;
+
+	const size_t watermark = (HREAD4(hp, SDHC_WATERMARK_LEVEL) >> SDHC_WATERMARK_READ_SHIFT) & SDHC_WATERMARK_READ_MASK;
+	size_t count = 0;
+
 	while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
-		uint32_t v = HREAD4(hp, SDHC_DATA);
+		if (count == 0) {
+			/*
+			 * If we've drained "watermark" words, we need to wait
+			 * a little bit so the read FIFO can refill.
+			 */
+			sdmmc_delay(10);
+			count = watermark;
+		}
+		v = HREAD4(hp, SDHC_DATA);
 		v = le32toh(v);
 		*(uint32_t *)data = v;
 		data += 4;
 		datalen -= 4;
 		status = HREAD2(hp, SDHC_NINTR_STATUS);
+		count--;
 	}
-
 	if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
-		uint32_t v = HREAD4(hp, SDHC_DATA);
+		if (count == 0) {
+			sdmmc_delay(10);
+		}
+		v = HREAD4(hp, SDHC_DATA);
 		v = le32toh(v);
 		do {
 			*data++ = v;
@@ -1402,16 +1415,29 @@ static void
 esdhc_write_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
 {
 	uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
+	uint32_t v;
+
+	const size_t watermark = (HREAD4(hp, SDHC_WATERMARK_LEVEL) >> SDHC_WATERMARK_WRITE_SHIFT) & SDHC_WATERMARK_WRITE_MASK;
+	size_t count = watermark;
+
 	while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
-		uint32_t v = *(uint32_t *)data;
+		if (count == 0) {
+			sdmmc_delay(10);
+			count = watermark;
+		}
+		v = *(uint32_t *)data;
 		v = htole32(v);
 		HWRITE4(hp, SDHC_DATA, v);
 		data += 4;
 		datalen -= 4;
 		status = HREAD2(hp, SDHC_NINTR_STATUS);
+		count--;
 	}
 	if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
-		uint32_t v = *(uint32_t *)data;
+		if (count == 0) {
+			sdmmc_delay(10);
+		}
+		v = *(uint32_t *)data;
 		v = htole32(v);
 		HWRITE4(hp, SDHC_DATA, v);
 	}
@@ -1505,8 +1531,9 @@ sdhc_intr(void *arg)
 			uint32_t xstatus = HREAD4(hp, SDHC_NINTR_STATUS);
 			status = xstatus;
 			error = xstatus >> 16;
-			status |= (error ? SDHC_ERROR_INTERRUPT : 0);
-			if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
+			if (error)
+				xstatus |= SDHC_ERROR_INTERRUPT;
+			else if (!ISSET(status, SDHC_NINTR_STATUS_MASK))
 				continue; /* no interrupt for us */
 			/* Acknowledge the interrupts we are about to handle. */
 			HWRITE4(hp, SDHC_NINTR_STATUS, xstatus);

Index: src/sys/dev/sdmmc/sdhcreg.h
diff -u src/sys/dev/sdmmc/sdhcreg.h:1.5 src/sys/dev/sdmmc/sdhcreg.h:1.5.2.1
--- src/sys/dev/sdmmc/sdhcreg.h:1.5	Wed Feb  1 22:53:19 2012
+++ src/sys/dev/sdmmc/sdhcreg.h	Wed Aug  8 06:18:59 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdhcreg.h,v 1.5 2012/02/01 22:53:19 matt Exp $	*/
+/*	$NetBSD: sdhcreg.h,v 1.5.2.1 2012/08/08 06:18:59 jdc Exp $	*/
 /*	$OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $	*/
 
 /*
@@ -152,6 +152,11 @@
 #define  SDHC_TIMEOUT_FREQ_UNIT		(1<<7)	/* 0=KHz, 1=MHz */
 #define  SDHC_TIMEOUT_FREQ_SHIFT	0
 #define  SDHC_TIMEOUT_FREQ_MASK		0x1f
+#define	SDHC_WATERMARK_LEVEL		0x44	/* ESDHC */
+#define	 SDHC_WATERMARK_WRITE_SHIFT	16
+#define	 SDHC_WATERMARK_WRITE_MASK	0xff
+#define	 SDHC_WATERMARK_READ_SHIFT	0
+#define	 SDHC_WATERMARK_READ_MASK	0xff
 #define SDHC_MAX_CAPABILITIES		0x48
 #define	SDHC_HOST_VER			0xFC
 #define  SDHC_VVN_MASK			0x0f

Index: src/sys/dev/sdmmc/sdmmc_mem.c
diff -u src/sys/dev/sdmmc/sdmmc_mem.c:1.20 src/sys/dev/sdmmc/sdmmc_mem.c:1.20.2.1
--- src/sys/dev/sdmmc/sdmmc_mem.c:1.20	Wed Feb  1 22:34:43 2012
+++ src/sys/dev/sdmmc/sdmmc_mem.c	Wed Aug  8 06:18:59 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmc_mem.c,v 1.20 2012/02/01 22:34:43 matt Exp $	*/
+/*	$NetBSD: sdmmc_mem.c,v 1.20.2.1 2012/08/08 06:18:59 jdc Exp $	*/
 /*	$OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -45,7 +45,7 @@
 /* Routines for SD/MMC memory cards. */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.20 2012/02/01 22:34:43 matt Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sdmmc_mem.c,v 1.20.2.1 2012/08/08 06:18:59 jdc Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -934,8 +934,6 @@ sdmmc_mem_decode_scr(struct sdmmc_softc 
 	resp[1] = be32toh(sf->raw_scr[0]);		// MSW
 	resp[0] |= (resp[1] & 0xff) << 24;
 	resp[1] >>= 8;
-	resp[0] = htole32(resp[0]);
-	resp[1] = htole32(resp[1]);
 
 	ver = SCR_STRUCTURE(resp);
 	sf->scr.sd_spec = SCR_SD_SPEC(resp);

Index: src/sys/dev/sdmmc/sdmmcreg.h
diff -u src/sys/dev/sdmmc/sdmmcreg.h:1.8 src/sys/dev/sdmmc/sdmmcreg.h:1.8.2.1
--- src/sys/dev/sdmmc/sdmmcreg.h:1.8	Fri Jan 27 03:07:21 2012
+++ src/sys/dev/sdmmc/sdmmcreg.h	Wed Aug  8 06:18:59 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: sdmmcreg.h,v 1.8 2012/01/27 03:07:21 matt Exp $	*/
+/*	$NetBSD: sdmmcreg.h,v 1.8.2.1 2012/08/08 06:18:59 jdc Exp $	*/
 /*	$OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $	*/
 
 /*
@@ -308,43 +308,35 @@
 #define SCR_SD_BUS_WIDTHS(scr)		MMC_RSP_BITS((scr), 48, 4)
 #define  SCR_SD_BUS_WIDTHS_1BIT		(1 << 0) /* 1bit (DAT0) */
 #define  SCR_SD_BUS_WIDTHS_4BIT		(1 << 2) /* 4bit (DAT0-3) */
-#define SCR_RESERVED(scr)		MMC_RSP_BITS((scr), 32, 16)
+#define SCR_SD_SPEC3(scr)		MMC_RSP_BITS((scr), 47, 1)
+#define SCR_EX_SECURITY(scr)		MMC_RSP_BITS((scr), 43, 4)
+#define SCR_RESERVED(scr)		MMC_RSP_BITS((scr), 34, 9)
+#define SCR_CMD_SUPPORT_CMD23(scr)	MMC_RSP_BITS((scr), 33, 1)
+#define SCR_CMD_SUPPORT_CMD20(scr)	MMC_RSP_BITS((scr), 32, 1)
 #define SCR_RESERVED2(scr)		MMC_RSP_BITS((scr), 0, 32)
 
 /* Status of Switch Function */
 #define SFUNC_STATUS_GROUP(status, group) \
 	be16toh(__bitfield((uint32_t *)(status), (7 - (group)) << 4, 16))
 
-/* Might be slow, but it should work on big and little endian systems. */
+/* This assumes the response fields are in host byte order in 32-bit units.  */
 #define MMC_RSP_BITS(resp, start, len)	__bitfield((resp), (start)-8, (len))
-static inline int
-__bitfield(uint32_t *src, int start, int len)
+static inline uint32_t
+__bitfield(const uint32_t *src, size_t start, size_t len)
 {
-	uint8_t *sp;
-	uint32_t dst, mask;
-	int shift, bs, bc;
-
-	if (start < 0 || len < 0 || len > 32)
+	if (start + len > 128 || len == 0 || len > 32)
 		return 0;
 
-	dst = 0;
-	mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX;
-	shift = 0;
-
-	while (len > 0) {
-		sp = (uint8_t *)src + start / 8;
-		bs = start % 8;
-		bc = 8 - bs;
-		if (bc > len)
-			bc = len;
-		dst |= (*sp >> bs) << shift;
-		shift += bc;
-		start += bc;
-		len -= bc;
+	src += start / 32;
+	start %= 32;
+
+	uint32_t dst = src[0] >> start;
+
+	if (__predict_false((start + len - 1) / 32 != start / 32)) {
+		dst |= src[1] << (32 - start);
 	}
 
-	dst &= mask;
-	return (int)dst;
+	return dst & (__BIT(len) - 1);
 }
 
 #endif	/* _SDMMCREG_H_ */

Reply via email to