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.
This commit is contained in:
parent
598818f0d2
commit
752fce8819
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: sdhc.c,v 1.22 2012/07/17 21:35:26 matt Exp $ */
|
/* $NetBSD: sdhc.c,v 1.23 2012/07/20 02:04:13 matt Exp $ */
|
||||||
/* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */
|
/* $OpenBSD: sdhc.c,v 1.25 2009/01/13 19:44:20 grange Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -23,7 +23,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#include <sys/cdefs.h>
|
||||||
__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.22 2012/07/17 21:35:26 matt Exp $");
|
__KERNEL_RCSID(0, "$NetBSD: sdhc.c,v 1.23 2012/07/20 02:04:13 matt Exp $");
|
||||||
|
|
||||||
#ifdef _KERNEL_OPT
|
#ifdef _KERNEL_OPT
|
||||||
#include "opt_sdmmc.h"
|
#include "opt_sdmmc.h"
|
||||||
@ -1012,23 +1012,15 @@ sdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
|
|||||||
*/
|
*/
|
||||||
mutex_enter(&hp->host_mtx);
|
mutex_enter(&hp->host_mtx);
|
||||||
if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
|
if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
|
||||||
uint32_t *p = cmd->c_resp;
|
cmd->c_resp[0] = HREAD4(hp, SDHC_RESPONSE + 0);
|
||||||
int i;
|
if (ISSET(cmd->c_flags, SCF_RSP_136)) {
|
||||||
|
cmd->c_resp[1] = HREAD4(hp, SDHC_RESPONSE + 4);
|
||||||
for (i = 0; i < 4; i++) {
|
cmd->c_resp[2] = HREAD4(hp, SDHC_RESPONSE + 8);
|
||||||
#ifdef __BUS_SPACE_HAS_STREAM_METHODS
|
cmd->c_resp[3] = HREAD4(hp, SDHC_RESPONSE + 12);
|
||||||
*p++ = bus_space_read_stream_4(hp->iot, hp->ioh,
|
|
||||||
SDHC_RESPONSE + i * 4);
|
|
||||||
#else
|
|
||||||
*p++ = htole32(bus_space_read_4(hp->iot, hp->ioh,
|
|
||||||
SDHC_RESPONSE + i * 4));
|
|
||||||
#endif
|
|
||||||
if (!ISSET(cmd->c_flags, SCF_RSP_136))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_exit(&hp->host_mtx);
|
mutex_exit(&hp->host_mtx);
|
||||||
DPRINTF(1,("%s: resp = %08x\n", HDEVNAME(hp), cmd->c_resp[0]));
|
DPRINTF(1,("%s: resp = %08x\n", HDEVNAME(hp), be32toh(cmd->c_resp[0])));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the command has data to transfer in any direction,
|
* If the command has data to transfer in any direction,
|
||||||
@ -1403,15 +1395,30 @@ esdhc_read_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
|
|||||||
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
|
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
|
||||||
uint32_t v;
|
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)) {
|
while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
|
||||||
|
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 = HREAD4(hp, SDHC_DATA);
|
||||||
v = le32toh(v);
|
v = le32toh(v);
|
||||||
*(uint32_t *)data = v;
|
*(uint32_t *)data = v;
|
||||||
data += 4;
|
data += 4;
|
||||||
datalen -= 4;
|
datalen -= 4;
|
||||||
status = HREAD2(hp, SDHC_NINTR_STATUS);
|
status = HREAD2(hp, SDHC_NINTR_STATUS);
|
||||||
|
count--;
|
||||||
}
|
}
|
||||||
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
|
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
|
||||||
|
if (count == 0) {
|
||||||
|
sdmmc_delay(10);
|
||||||
|
}
|
||||||
v = HREAD4(hp, SDHC_DATA);
|
v = HREAD4(hp, SDHC_DATA);
|
||||||
v = le32toh(v);
|
v = le32toh(v);
|
||||||
do {
|
do {
|
||||||
@ -1427,15 +1434,26 @@ esdhc_write_data_pio(struct sdhc_host *hp, uint8_t *data, u_int datalen)
|
|||||||
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
|
uint16_t status = HREAD2(hp, SDHC_NINTR_STATUS);
|
||||||
uint32_t v;
|
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)) {
|
while (datalen > 3 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
|
||||||
|
if (count == 0) {
|
||||||
|
sdmmc_delay(10);
|
||||||
|
count = watermark;
|
||||||
|
}
|
||||||
v = *(uint32_t *)data;
|
v = *(uint32_t *)data;
|
||||||
v = htole32(v);
|
v = htole32(v);
|
||||||
HWRITE4(hp, SDHC_DATA, v);
|
HWRITE4(hp, SDHC_DATA, v);
|
||||||
data += 4;
|
data += 4;
|
||||||
datalen -= 4;
|
datalen -= 4;
|
||||||
status = HREAD2(hp, SDHC_NINTR_STATUS);
|
status = HREAD2(hp, SDHC_NINTR_STATUS);
|
||||||
|
count--;
|
||||||
}
|
}
|
||||||
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
|
if (datalen > 0 && !ISSET(status, SDHC_TRANSFER_COMPLETE)) {
|
||||||
|
if (count == 0) {
|
||||||
|
sdmmc_delay(10);
|
||||||
|
}
|
||||||
v = *(uint32_t *)data;
|
v = *(uint32_t *)data;
|
||||||
v = htole32(v);
|
v = htole32(v);
|
||||||
HWRITE4(hp, SDHC_DATA, v);
|
HWRITE4(hp, SDHC_DATA, v);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: sdhcreg.h,v 1.7 2012/07/12 16:34:30 jakllsch Exp $ */
|
/* $NetBSD: sdhcreg.h,v 1.8 2012/07/20 02:04:13 matt Exp $ */
|
||||||
/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */
|
/* $OpenBSD: sdhcreg.h,v 1.4 2006/07/30 17:20:40 fgsch Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -154,6 +154,11 @@
|
|||||||
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
#define SDHC_TIMEOUT_FREQ_UNIT (1<<7) /* 0=KHz, 1=MHz */
|
||||||
#define SDHC_TIMEOUT_FREQ_SHIFT 0
|
#define SDHC_TIMEOUT_FREQ_SHIFT 0
|
||||||
#define SDHC_TIMEOUT_FREQ_MASK 0x1f
|
#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_MAX_CAPABILITIES 0x48
|
||||||
#define SDHC_HOST_VER 0xFC
|
#define SDHC_HOST_VER 0xFC
|
||||||
#define SDHC_VVN_MASK 0x0f
|
#define SDHC_VVN_MASK 0x0f
|
||||||
|
@ -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.21 2012/07/20 02:04:13 matt Exp $ */
|
||||||
/* $OpenBSD: sdmmc_mem.c,v 1.10 2009/01/09 10:55:22 jsg 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. */
|
/* Routines for SD/MMC memory cards. */
|
||||||
|
|
||||||
#include <sys/cdefs.h>
|
#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.21 2012/07/20 02:04:13 matt Exp $");
|
||||||
|
|
||||||
#ifdef _KERNEL_OPT
|
#ifdef _KERNEL_OPT
|
||||||
#include "opt_sdmmc.h"
|
#include "opt_sdmmc.h"
|
||||||
@ -934,8 +934,8 @@ sdmmc_mem_decode_scr(struct sdmmc_softc *sc, struct sdmmc_function *sf)
|
|||||||
resp[1] = be32toh(sf->raw_scr[0]); // MSW
|
resp[1] = be32toh(sf->raw_scr[0]); // MSW
|
||||||
resp[0] |= (resp[1] & 0xff) << 24;
|
resp[0] |= (resp[1] & 0xff) << 24;
|
||||||
resp[1] >>= 8;
|
resp[1] >>= 8;
|
||||||
resp[0] = htole32(resp[0]);
|
resp[0] = htobe32(resp[0]);
|
||||||
resp[1] = htole32(resp[1]);
|
resp[1] = htobe32(resp[1]);
|
||||||
|
|
||||||
ver = SCR_STRUCTURE(resp);
|
ver = SCR_STRUCTURE(resp);
|
||||||
sf->scr.sd_spec = SCR_SD_SPEC(resp);
|
sf->scr.sd_spec = SCR_SD_SPEC(resp);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* $NetBSD: sdmmcreg.h,v 1.9 2012/07/12 16:03:13 jakllsch Exp $ */
|
/* $NetBSD: sdmmcreg.h,v 1.10 2012/07/20 02:04:13 matt Exp $ */
|
||||||
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
|
/* $OpenBSD: sdmmcreg.h,v 1.4 2009/01/09 10:55:22 jsg Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -309,43 +309,35 @@
|
|||||||
#define SCR_SD_BUS_WIDTHS(scr) MMC_RSP_BITS((scr), 48, 4)
|
#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_1BIT (1 << 0) /* 1bit (DAT0) */
|
||||||
#define SCR_SD_BUS_WIDTHS_4BIT (1 << 2) /* 4bit (DAT0-3) */
|
#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)
|
#define SCR_RESERVED2(scr) MMC_RSP_BITS((scr), 0, 32)
|
||||||
|
|
||||||
/* Status of Switch Function */
|
/* Status of Switch Function */
|
||||||
#define SFUNC_STATUS_GROUP(status, group) \
|
#define SFUNC_STATUS_GROUP(status, group) \
|
||||||
be16toh(__bitfield((uint32_t *)(status), (7 - (group)) << 4, 16))
|
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 big endian order. */
|
||||||
#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
|
#define MMC_RSP_BITS(resp, start, len) __bitfield((resp), (start)-8, (len))
|
||||||
static inline int
|
static inline uint32_t
|
||||||
__bitfield(uint32_t *src, int start, int len)
|
__bitfield(const uint32_t *src, size_t start, size_t len)
|
||||||
{
|
{
|
||||||
uint8_t *sp;
|
if (start + len > 128 || len == 0 || len > 32)
|
||||||
uint32_t dst, mask;
|
|
||||||
int shift, bs, bc;
|
|
||||||
|
|
||||||
if (start < 0 || len < 0 || len > 32)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
dst = 0;
|
src += start / 32;
|
||||||
mask = len % 32 ? UINT_MAX >> (32 - (len % 32)) : UINT_MAX;
|
start %= 32;
|
||||||
shift = 0;
|
|
||||||
|
|
||||||
while (len > 0) {
|
uint32_t dst = be32toh(src[0]) >> start;
|
||||||
sp = (uint8_t *)src + start / 8;
|
|
||||||
bs = start % 8;
|
if (__predict_false((start + len - 1) / 32 != start / 32)) {
|
||||||
bc = 8 - bs;
|
dst |= be32toh(src[1]) << (32 - start);
|
||||||
if (bc > len)
|
|
||||||
bc = len;
|
|
||||||
dst |= (*sp >> bs) << shift;
|
|
||||||
shift += bc;
|
|
||||||
start += bc;
|
|
||||||
len -= bc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dst &= mask;
|
return dst & (__BIT(len) - 1);
|
||||||
return (int)dst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _SDMMCREG_H_ */
|
#endif /* _SDMMCREG_H_ */
|
||||||
|
Loading…
Reference in New Issue
Block a user