Contribution from Petri Laakso: Initial support for SD card controller.

iMX233-OLinuXino can now boot and run from its own SD card.
This commit is contained in:
jkunz 2012-12-16 19:45:52 +00:00
parent 8a7d722d8b
commit c332c3c01b
2 changed files with 231 additions and 130 deletions

View File

@ -1,4 +1,4 @@
/* $Id: imx23_ssp.c,v 1.1 2012/11/20 19:06:14 jkunz Exp $ */
/* $Id: imx23_ssp.c,v 1.2 2012/12/16 19:45:52 jkunz Exp $ */
/*
* Copyright (c) 2012 The NetBSD Foundation, Inc.
@ -33,15 +33,10 @@
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/cdefs.h>
#include <sys/cpu.h>
#include <sys/device.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <arm/pic/picvar.h>
#include <arm/imx/imx23_apbdma.h>
#include <arm/imx/imx23_icollreg.h>
#include <arm/imx/imx23_sspreg.h>
#include <arm/imx/imx23var.h>
@ -50,7 +45,7 @@
#include <dev/sdmmc/sdmmcvar.h>
/*
* SD/MMC host controller driver for i.MX233.
* SD/MMC host controller driver for i.MX23.
*/
struct issp_softc {
@ -65,7 +60,11 @@ static int issp_match(device_t, cfdata_t, void *);
static void issp_attach(device_t, device_t, void *);
static int issp_activate(device_t, enum devact);
/* sdmmc chip function prototypes. */
static void issp_reset(struct issp_softc *);
static void issp_init(struct issp_softc *);
static uint32_t issp_set_sck(struct issp_softc *, uint32_t target);
/* sdmmc(4) driver chip function prototypes. */
static int issp_host_reset(sdmmc_chipset_handle_t);
static uint32_t issp_host_ocr(sdmmc_chipset_handle_t);
static int issp_host_maxblklen(sdmmc_chipset_handle_t);
@ -80,23 +79,6 @@ static void issp_exec_command(sdmmc_chipset_handle_t,
static void issp_card_enable_intr(sdmmc_chipset_handle_t, int);
static void issp_card_intr_ack(sdmmc_chipset_handle_t);
/* Used from the above callbacks. */
static void issp_reset(struct issp_softc *);
static void issp_init(struct issp_softc *);
static uint32_t issp_set_sck(struct issp_softc *, uint32_t target);
#define SSP_SOFT_RST_LOOP 455 /* At least 1 us ... */
CFATTACH_DECL3_NEW(ssp,
sizeof(struct issp_softc),
issp_match,
issp_attach,
NULL,
issp_activate,
NULL,
NULL,
0);
static struct sdmmc_chip_functions issp_functions = {
.host_reset = issp_host_reset,
.host_ocr = issp_host_ocr,
@ -112,22 +94,45 @@ static struct sdmmc_chip_functions issp_functions = {
.card_intr_ack = issp_card_intr_ack
};
#define SSP_READ(sc, reg) \
CFATTACH_DECL3_NEW(ssp,
sizeof(struct issp_softc),
issp_match,
issp_attach,
NULL,
issp_activate,
NULL,
NULL,
0);
#define SSP_SOFT_RST_LOOP 455 /* At least 1 us ... */
#define SSP_RD(sc, reg) \
bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg))
#define SSP_WRITE(sc, reg, val) \
#define SSP_WR(sc, reg, val) \
bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val))
#define SSP_CLK 96000000 /* CLK_SSP from PLL is 96 MHz */
#define SSP_CLK_MIN 2 /* 2 kHz */
#define SSP_CLK_MAX 48000 /* 48 MHz */
/* SSP_CMD_TIMEOUT is calculated as (1.0/SSP_SCK)*(SSP_CMD_TIMEOUT*4096) */
#define SSP_CMD_TIMEOUT 0xffff /* 2.8 seconds. */
#define SSP_STATUS_ERR (HW_SSP_STATUS_RESP_CRC_ERR | \
#define SSP_CLK 96000000 /* CLK_SSP from PLL is 96 MHz */
#define SSP_CLK_MIN 400 /* 400 kHz */
#define SSP_CLK_MAX 48000 /* 48 MHz */
#define SSP_BUSY (HW_SSP_STATUS_CMD_BUSY | \
HW_SSP_STATUS_DATA_BUSY | \
HW_SSP_STATUS_BUSY)
#define SSP_RUN_ERR (HW_SSP_STATUS_RESP_CRC_ERR | \
HW_SSP_STATUS_RESP_ERR | \
HW_SSP_STATUS_RESP_TIMEOUT | \
HW_SSP_STATUS_DATA_CRC_ERR | \
HW_SSP_STATUS_TIMEOUT)
#define BLKIO_NONE 0
#define BLKIO_RD 1
#define BLKIO_WR 2
#define BUS_WIDTH_1_BIT 0x0
#define BUS_WIDTH_4_BIT 0x1
#define BUS_WIDTH_8_BIT 0x2
static int
issp_match(device_t parent, cfdata_t match, void *aux)
{
@ -145,25 +150,18 @@ issp_match(device_t parent, cfdata_t match, void *aux)
static void
issp_attach(device_t parent, device_t self, void *aux)
{
static int issp_attached = 0;
struct issp_softc *sc = device_private(self);
struct apb_softc *scp = device_private(parent);
struct apb_softc *sc_parent = device_private(parent);
struct apb_attach_args *aa = aux;
struct sdmmcbus_attach_args saa;
static int issp_attached = 0;
if (issp_attached)
return;
//XXX:
if (scp == NULL)
printf("ISSP_ATTACH: scp == NULL\n");
if (scp->dmac == NULL)
printf("ISSP_ATTACH: scp->dmac == NULL\n");
sc->sc_dev = self;
sc->sc_iot = aa->aa_iot;
sc->dmac = scp->dmac;
sc->dmac = sc_parent->dmac;
if (bus_space_map(sc->sc_iot,
aa->aa_addr, aa->aa_size, 0, &(sc->sc_hdl))) {
@ -172,9 +170,9 @@ issp_attach(device_t parent, device_t self, void *aux)
}
issp_reset(sc);
issp_init(sc);
issp_init(sc);
uint32_t issp_vers = SSP_READ(sc, HW_SSP_VERSION);
uint32_t issp_vers = SSP_RD(sc, HW_SSP_VERSION);
aprint_normal(": SSP Block v%" __PRIuBIT ".%" __PRIuBIT "\n",
__SHIFTOUT(issp_vers, HW_SSP_VERSION_MAJOR),
__SHIFTOUT(issp_vers, HW_SSP_VERSION_MINOR));
@ -186,7 +184,8 @@ issp_attach(device_t parent, device_t self, void *aux)
saa.saa_dmat = aa->aa_dmat;
saa.saa_clkmin = SSP_CLK_MIN;
saa.saa_clkmax = SSP_CLK_MAX;
saa.saa_caps = SMC_CAPS_4BIT_MODE | SMC_CAPS_DMA;
/* Add SMC_CAPS_DMA capability when DMA funtionality is implemented. */
saa.saa_caps = SMC_CAPS_4BIT_MODE | SMC_CAPS_SINGLE_ONLY;
sc->sc_sdmmc = config_found(sc->sc_dev, &saa, NULL);
if (sc->sc_sdmmc == NULL) {
@ -228,7 +227,6 @@ issp_host_ocr(sdmmc_chipset_handle_t sch)
static int
issp_host_maxblklen(sdmmc_chipset_handle_t sch)
{
/* XXX: This value was made up. */
return 512;
}
@ -242,10 +240,10 @@ issp_card_detect(sdmmc_chipset_handle_t sch)
/* struct issp_softc *sc = sch;
*
* In the perfect world I'll just:
* return SSP_READ(sc, HW_SSP_STATUS) & HW_SSP_STATUS_CARD_DETECT;
* return SSP_RD(sc, HW_SSP_STATUS) & HW_SSP_STATUS_CARD_DETECT;
* and call it a day.
*
* But on i.MX233 OLinuXino MAXI, SSP1_DETECT is not used for the SD
* But on i.MX23 OLinuXino MAXI, SSP1_DETECT is not used for the SD
* card detection but SSP1_DATA3 is, as Tsvetan put it:
*
* < Tsvetan> if you want to know if SD card is inserted watch
@ -258,7 +256,7 @@ issp_card_detect(sdmmc_chipset_handle_t sch)
* #if BOARDTYPE == MAXI (Possibly MINI & MICRO)
* return GPIO_READ(PIN_125) & PIN_125
* #else
* return SSP_READ(sc, STATUS) & CARD_DETECT;
* return SSP_RD(sc, STATUS) & CARD_DETECT;
* #endif
* Until GPIO functionality is not present I am just going to */
@ -273,9 +271,9 @@ issp_write_protect(sdmmc_chipset_handle_t sch)
}
static int
issp_bus_power(sdmmc_chipset_handle_t sch, uint32_t power)
issp_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
{
/* i.MX233 does not support setting bus power. */
/* i.MX23 SSP does not support setting bus power. */
return 0;
}
@ -285,9 +283,13 @@ issp_bus_clock(sdmmc_chipset_handle_t sch, int clock)
struct issp_softc *sc = sch;
uint32_t sck;
aprint_normal_dev(sc->sc_dev, "requested clock %d Hz", clock * 1000);
sck = issp_set_sck(sc, clock * 1000);
aprint_normal(", got %d Hz\n", sck);
/* Notify user if we didn't get exact clock rate from SSP that was
* requested. */
if (sck != clock * 1000)
aprint_normal_dev(sc->sc_dev, "requested clock %dHz, "
"but got %dHz\n", clock * 1000, sck);
return 0;
}
@ -295,8 +297,29 @@ issp_bus_clock(sdmmc_chipset_handle_t sch, int clock)
static int
issp_bus_width(sdmmc_chipset_handle_t sch, int width)
{
/* Return error if other than 4-bit width is requested. */
return width - 4;
struct issp_softc *sc = sch;
uint32_t reg;
reg = SSP_RD(sc, HW_SSP_CTRL0);
reg &= ~(HW_SSP_CTRL0_BUS_WIDTH);
switch(width) {
case(1):
reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH);
break;
case(4):
reg |= __SHIFTIN(BUS_WIDTH_4_BIT, HW_SSP_CTRL0_BUS_WIDTH);
break;
case(8):
reg |= __SHIFTIN(BUS_WIDTH_8_BIT, HW_SSP_CTRL0_BUS_WIDTH);
break;
default:
return 1;
}
SSP_WR(sc, HW_SSP_CTRL0, reg);
return 0;
}
static int
@ -311,60 +334,130 @@ issp_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
{
struct issp_softc *sc = sch;
uint32_t reg;
uint32_t do_blkio;
uint32_t i;
/* Set excepted response type. */
SSP_WRITE(sc, HW_SSP_CTRL0_CLR,
do_blkio = 0;
/* Wait until SSP done. (data I/O error + retry...) */
while (SSP_RD(sc, HW_SSP_STATUS) & SSP_BUSY)
;
/* Set expected response type. */
SSP_WR(sc, HW_SSP_CTRL0_CLR,
HW_SSP_CTRL0_GET_RESP | HW_SSP_CTRL0_LONG_RESP);
if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_GET_RESP);
SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_GET_RESP);
if (ISSET(cmd->c_flags, SCF_RSP_136))
SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_LONG_RESP);
SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_LONG_RESP);
}
/* If CMD does not need CRC validation, tell it to SSP. */
if (ISSET(cmd->c_flags, SCF_RSP_CRC))
SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_IGNORE_CRC);
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_IGNORE_CRC);
else
SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_IGNORE_CRC);
SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_IGNORE_CRC);
/* Set command. */
SSP_WRITE(sc, HW_SSP_CMD0_CLR, HW_SSP_CMD0_CMD);
SSP_WRITE(sc, HW_SSP_CMD0_SET,
SSP_WR(sc, HW_SSP_CMD0_CLR, HW_SSP_CMD0_CMD);
SSP_WR(sc, HW_SSP_CMD0_SET,
__SHIFTIN(cmd->c_opcode, HW_SSP_CMD0_CMD));
/* Set command argument. */
SSP_WRITE(sc, HW_SSP_CMD1, cmd->c_arg);
SSP_WR(sc, HW_SSP_CMD1, cmd->c_arg);
/* Is data to be transferred? */
if (cmd->c_datalen > 0 && cmd->c_data != NULL) {
SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_DATA_XFER);
/* Transfer XFER_COUNT of 8-bit words. */
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_XFER_COUNT);
SSP_WR(sc, HW_SSP_CTRL0_SET,
__SHIFTIN(cmd->c_datalen, HW_SSP_CTRL0_XFER_COUNT));
/* XXX: why 8CYC? Bit is never cleaned. */
SSP_WR(sc, HW_SSP_CMD0_SET, HW_SSP_CMD0_APPEND_8CYC);
if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
/* Read mode. */
do_blkio |= BLKIO_RD;
SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_READ);
} else {
/* Write mode. */
do_blkio |= BLKIO_WR;
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_READ);
}
} else {
/* No data to be transferred. */
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_DATA_XFER);
}
/* Run the command. */
SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_RUN);
SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_RUN);
/* Wait until SSP has processed the command. */
while (SSP_READ(sc, HW_SSP_STATUS) &
(HW_SSP_STATUS_CMD_BUSY | HW_SSP_STATUS_BUSY))
;
/* Check if the command ran without errors. */
reg = SSP_READ(sc, HW_SSP_STATUS);
if (reg & SSP_STATUS_ERR)
cmd->c_error = reg & SSP_STATUS_ERR;
/* Read response if such was requested. */
if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
cmd->c_resp[0] = SSP_READ(sc, HW_SSP_SDRESP0);
if (ISSET(cmd->c_flags, SCF_RSP_136)) {
cmd->c_resp[1] = SSP_READ(sc, HW_SSP_SDRESP1);
cmd->c_resp[2] = SSP_READ(sc, HW_SSP_SDRESP2);
cmd->c_resp[3] = SSP_READ(sc, HW_SSP_SDRESP3);
if (ISSET(do_blkio, BLKIO_RD)) {
for (i = 0; i < cmd->c_datalen / 4; i++) {
/* Wait until data arrives to FIFO. */
while (SSP_RD(sc, HW_SSP_STATUS)
& HW_SSP_STATUS_FIFO_EMPTY) {
/* Abort if error while waiting. */
if (SSP_RD(sc, HW_SSP_STATUS) & SSP_RUN_ERR) {
aprint_normal_dev(sc->sc_dev,
"RD_ERR: %x\n",
SSP_RD(sc, HW_SSP_STATUS));
cmd->c_error = 1;
goto pioerr;
}
}
*((uint32_t *)cmd->c_data+i) = SSP_RD(sc, HW_SSP_DATA);
}
} else if (ISSET(do_blkio, BLKIO_WR)) {
for (i = 0; i < (cmd->c_datalen / 4); i++) {
while (SSP_RD(sc, HW_SSP_STATUS)
& HW_SSP_STATUS_FIFO_FULL) {
/* Abort if error while waiting. */
if (SSP_RD(sc, HW_SSP_STATUS) & SSP_RUN_ERR) {
aprint_normal_dev(sc->sc_dev,
"WR_ERR: %x\n",
SSP_RD(sc, HW_SSP_STATUS));
cmd->c_error = 1;
goto pioerr;
}
}
SSP_WR(sc, HW_SSP_DATA, *((uint32_t *)cmd->c_data+i));
}
}
/*
apbdma_dmamem_alloc()
apbdma_do_dma()
wait_until_done()
*/
/* Wait until SSP is done. */
while (SSP_RD(sc, HW_SSP_STATUS) & SSP_BUSY)
;
/* Check if the command ran successfully. */
reg = SSP_RD(sc, HW_SSP_STATUS);
if (reg & SSP_RUN_ERR)
cmd->c_error = reg & SSP_RUN_ERR;
/* Read response if such was requested. */
if (ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
cmd->c_resp[0] = SSP_RD(sc, HW_SSP_SDRESP0);
if (ISSET(cmd->c_flags, SCF_RSP_136)) {
cmd->c_resp[1] = SSP_RD(sc, HW_SSP_SDRESP1);
cmd->c_resp[2] = SSP_RD(sc, HW_SSP_SDRESP2);
cmd->c_resp[3] = SSP_RD(sc, HW_SSP_SDRESP3);
/*
* Remove CRC7 + LSB by rotating all bits right by 8 to
* make sdmmc __bitfield() happy.
*/
cmd->c_resp[0] >>= 8; /* Remove CRC7 + LSB. */
cmd->c_resp[0] |= (0x000000FF & cmd->c_resp[1]) << 24;
cmd->c_resp[1] >>= 8;
cmd->c_resp[1] |= (0x000000FF & cmd->c_resp[2]) << 24;
cmd->c_resp[2] >>= 8;
cmd->c_resp[2] |= (0x000000FF & cmd->c_resp[3]) << 24;
cmd->c_resp[3] >>= 8;
}
}
pioerr:
return;
}
@ -374,7 +467,7 @@ issp_card_enable_intr(sdmmc_chipset_handle_t sch, int irq)
struct issp_softc *sc = sch;
aprint_normal_dev(sc->sc_dev,
"issp_card_enable_intr NOT IMPLEMENTED!\n");
"issp_card_enable_intr NOT IMPLEMENTED!\n");
return;
}
@ -392,7 +485,7 @@ issp_card_intr_ack(sdmmc_chipset_handle_t sch)
/*
* Reset the SSP block.
*
* Inspired by i.MX233 RM "39.3.10 Correct Way to Soft Reset a Block"
* Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block"
*/
static void
issp_reset(struct issp_softc *sc)
@ -402,65 +495,77 @@ issp_reset(struct issp_softc *sc)
/* Prepare for soft-reset by making sure that SFTRST is not currently
* asserted. Also clear CLKGATE so we can wait for its assertion below.
*/
SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
/* Wait at least a microsecond for SFTRST to deassert. */
loop = 0;
while ((SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
(loop < SSP_SOFT_RST_LOOP))
loop++;
/* Clear CLKGATE so we can wait for its assertion below. */
SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
/* Soft-reset the block. */
SSP_WRITE(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST);
SSP_WR(sc, HW_SSP_CTRL0_SET, HW_SSP_CTRL0_SFTRST);
/* Wait until clock is in the gated state. */
while (!(SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE));
while (!(SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE));
/* Bring block out of reset. */
SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_SFTRST);
loop = 0;
while ((SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
while ((SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_SFTRST) ||
(loop < SSP_SOFT_RST_LOOP))
loop++;
SSP_WRITE(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
SSP_WR(sc, HW_SSP_CTRL0_CLR, HW_SSP_CTRL0_CLKGATE);
/* Wait until clock is in the NON-gated state. */
while (SSP_READ(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE);
while (SSP_RD(sc, HW_SSP_CTRL0) & HW_SSP_CTRL0_CLKGATE);
return;
}
/*
* Initialize common options.
* DATA_TIMEOUT is calculated as:
* (1 / SSP_CLK) * (DATA_TIMEOUT * 4096)
*/
#define DATA_TIMEOUT 0x4240 /* 723ms */
/*
* Initialize SSP controller to SD/MMC mode.
*/
static void
issp_init(struct issp_softc *sc)
{
uint32_t reg;
/* Initialize SD/MMC controller. */
reg = SSP_READ(sc, HW_SSP_CTRL0);
/* Initial data bus width is 1-bit. */
reg = SSP_RD(sc, HW_SSP_CTRL0);
reg &= ~(HW_SSP_CTRL0_BUS_WIDTH);
reg |= __SHIFTIN(0x1, HW_SSP_CTRL0_BUS_WIDTH) | HW_SSP_CTRL0_ENABLE;
SSP_WRITE(sc, HW_SSP_CTRL0, reg);
reg |= __SHIFTIN(BUS_WIDTH_1_BIT, HW_SSP_CTRL0_BUS_WIDTH) |
HW_SSP_CTRL0_WAIT_FOR_IRQ | HW_SSP_CTRL0_ENABLE;
SSP_WR(sc, HW_SSP_CTRL0, reg);
reg = SSP_READ(sc, HW_SSP_CTRL1);
/* Set data timeout. */
reg = SSP_RD(sc, HW_SSP_TIMING);
reg &= ~(HW_SSP_TIMING_TIMEOUT);
reg |= __SHIFTIN(DATA_TIMEOUT, HW_SSP_TIMING_TIMEOUT);
/* Set initial clock rate to minimum. */
issp_set_sck(sc, SSP_CLK_MIN * 1000);
SSP_WR(sc, HW_SSP_TIMING, reg);
/* Enable SD/MMC mode and use use 8-bits per word. */
reg = SSP_RD(sc, HW_SSP_CTRL1);
reg &= ~(HW_SSP_CTRL1_WORD_LENGTH | HW_SSP_CTRL1_SSP_MODE);
reg |= HW_SSP_CTRL1_POLARITY |
__SHIFTIN(0x7, HW_SSP_CTRL1_WORD_LENGTH) |
__SHIFTIN(0x3, HW_SSP_CTRL1_SSP_MODE);
SSP_WRITE(sc, HW_SSP_CTRL1, reg);
/* Set command timeout. */
reg = SSP_READ(sc, HW_SSP_TIMING);
reg &= ~(HW_SSP_TIMING_TIMEOUT);
reg |= __SHIFTIN(SSP_CMD_TIMEOUT, HW_SSP_TIMING_TIMEOUT);
SSP_WRITE(sc, HW_SSP_TIMING, reg);
SSP_WR(sc, HW_SSP_CTRL1, reg);
return;
}
@ -499,11 +604,11 @@ issp_set_sck(struct issp_softc *sc, uint32_t target)
}
}
out:
reg = SSP_READ(sc, HW_SSP_TIMING);
reg = SSP_RD(sc, HW_SSP_TIMING);
reg &= ~(HW_SSP_TIMING_CLOCK_DIVIDE | HW_SSP_TIMING_CLOCK_RATE);
reg |= __SHIFTIN(div, HW_SSP_TIMING_CLOCK_DIVIDE) |
__SHIFTIN(rate, HW_SSP_TIMING_CLOCK_RATE);
SSP_WRITE(sc, HW_SSP_TIMING, reg);
SSP_WR(sc, HW_SSP_TIMING, reg);
return SSP_CLK / (d * (1 + r));
return SSP_CLK / (div * (1 + rate));
}

View File

@ -1,4 +1,4 @@
# $Id: IMX23_OLINUXINO,v 1.1 2012/11/20 19:08:45 jkunz Exp $
# $Id: IMX23_OLINUXINO,v 1.2 2012/12/16 19:45:52 jkunz Exp $
#
# IMX23_OLINUXINO -- Olimex i.MX23 OLinuXino kernel configuration file.
#
@ -7,7 +7,7 @@ include "arch/evbarm/conf/std.imx23_olinuxino"
maxusers 8
config netbsd root on ? type ?
config netbsd root on ld0a type ?
# The main bus device
mainbus0 at root
@ -25,9 +25,9 @@ apbh0 at mainbus? base 0x80000000 size 0x00040000
icoll0 at apbh? addr 0x80000000 size 0x2000 irq -1
# Synchronous serial port for SD/MMC
#ssp0 at apbh? addr 0x80010000 size 0x2000 irq 15
#sdmmc* at ssp?
#ld* at sdmmc?
ssp0 at apbh? addr 0x80010000 size 0x2000 irq 15
sdmmc* at ssp?
ld* at sdmmc?
# APBX bus
apbx0 at mainbus? base 0x80040000 size 0x00040000
@ -47,11 +47,7 @@ options MEMSIZE=64
options DDB
options HZ=100
options MEMORY_DISK_HOOKS
options MEMORY_DISK_IS_ROOT
options MEMORY_DISK_ROOT_SIZE=12288 # 6 megs
options MEMORY_DISK_RBFLAGS=RB_SINGLE
pseudo-device md
file-system FFS
file-system EXT2FS
file-system MSDOSFS