diff options
| -rw-r--r-- | target/linux/at91-2.6/config/default | 1 | ||||
| -rw-r--r-- | target/linux/at91-2.6/patches/012-at91-mmcfix.patch | 424 | ||||
| -rw-r--r-- | target/linux/at91-2.6/patches/013-at91-mmc1wire.patch | 12 | 
3 files changed, 436 insertions, 1 deletions
diff --git a/target/linux/at91-2.6/config/default b/target/linux/at91-2.6/config/default index df916aad2..ec0a74190 100644 --- a/target/linux/at91-2.6/config/default +++ b/target/linux/at91-2.6/config/default @@ -123,7 +123,6 @@ CONFIG_HARDIRQS_SW_RESEND=y  CONFIG_HAS_IOMEM=y  CONFIG_HAS_IOPORT=y  CONFIG_HID=y -# CONFIG_HID_DEBUG is not set  CONFIG_HW_CONSOLE=y  # CONFIG_HW_RANDOM is not set  # CONFIG_I2C is not set diff --git a/target/linux/at91-2.6/patches/012-at91-mmcfix.patch b/target/linux/at91-2.6/patches/012-at91-mmcfix.patch new file mode 100644 index 000000000..e8991ae61 --- /dev/null +++ b/target/linux/at91-2.6/patches/012-at91-mmcfix.patch @@ -0,0 +1,424 @@ +--- linux-2.6.21.1.old/drivers/mmc/at91_mci.c	2007-06-05 09:08:57.000000000 +0200 ++++ linux-2.6.21.1/drivers/mmc/at91_mci.c	2007-06-05 10:59:11.000000000 +0200 +@@ -79,7 +79,8 @@ +  + #define DRIVER_NAME "at91_mci" +  +-#undef	SUPPORT_4WIRE ++//#undef	SUPPORT_4WIRE ++#define 	SUPPORT_4WIRE +  + #define FL_SENT_COMMAND	(1 << 0) + #define FL_SENT_STOP	(1 << 1) +@@ -132,7 +133,7 @@ + /* +  * Copy from sg to a dma block - used for transfers +  */ +-static inline void at91mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) ++static inline void at91_mci_sg_to_dma(struct at91mci_host *host, struct mmc_data *data) + { + 	unsigned int len, i, size; + 	unsigned *dmabuf = host->buffer; +@@ -181,7 +182,7 @@ + /* +  * Prepare a dma read +  */ +-static void at91mci_pre_dma_read(struct at91mci_host *host) ++static void at91_mci_pre_dma_read(struct at91mci_host *host) + { + 	int i; + 	struct scatterlist *sg; +@@ -249,23 +250,24 @@ + /* +  * Handle after a dma read +  */ +-static void at91mci_post_dma_read(struct at91mci_host *host) ++static int at91_mci_post_dma_read(struct at91mci_host *host) + { + 	struct mmc_command *cmd; + 	struct mmc_data *data; ++	int completed = 0; +  + 	pr_debug("post dma read\n"); +  + 	cmd = host->cmd; + 	if (!cmd) { + 		pr_debug("no command\n"); +-		return; ++		return 1; + 	} +  + 	data = cmd->data; + 	if (!data) { + 		pr_debug("no data\n"); +-		return; ++		return 1; + 	} +  + 	while (host->in_use_index < host->transfer_index) { +@@ -300,39 +302,14 @@ +  + 	/* Is there another transfer to trigger? */ + 	if (host->transfer_index < data->sg_len) +-		at91mci_pre_dma_read(host); ++		at91_mci_pre_dma_read(host); + 	else { ++		at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_ENDRX); + 		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF); +-		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); + 	} +  + 	pr_debug("post dma read done\n"); +-} +- +-/* +- * Handle transmitted data +- */ +-static void at91_mci_handle_transmitted(struct at91mci_host *host) +-{ +-	struct mmc_command *cmd; +-	struct mmc_data *data; +- +-	pr_debug("Handling the transmit\n"); +- +-	/* Disable the transfer */ +-	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); +- +-	/* Now wait for cmd ready */ +-	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); +-	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); +- +-	cmd = host->cmd; +-	if (!cmd) return; +- +-	data = cmd->data; +-	if (!data) return; +- +-	data->bytes_xfered = host->total_length; ++	return completed; + } +  + /* +@@ -340,10 +317,17 @@ +  */ + static void at91_mci_enable(struct at91mci_host *host) + { ++	unsigned int mr; ++ + 	at91_mci_write(host, AT91_MCI_CR, AT91_MCI_MCIEN); + 	at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); + 	at91_mci_write(host, AT91_MCI_DTOR, AT91_MCI_DTOMUL_1M | AT91_MCI_DTOCYC); +-	at91_mci_write(host, AT91_MCI_MR, AT91_MCI_PDCMODE | 0x34a); ++	mr = AT91_MCI_PDCMODE | 0x34a; ++ ++	if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) ++		mr |= AT91_MCI_RDPROOF | AT91_MCI_WRPROOF; ++ ++	at91_mci_write(host, AT91_MCI_MR, mr); +  + 	/* use Slot A or B (only one at same time) */ + 	at91_mci_write(host, AT91_MCI_SDCR, host->board->slot_b); +@@ -359,9 +343,8 @@ +  + /* +  * Send a command +- * return the interrupts to enable +  */ +-static unsigned int at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) ++static void at91_mci_send_command(struct at91mci_host *host, struct mmc_command *cmd) + { + 	unsigned int cmdr, mr; + 	unsigned int block_length; +@@ -372,8 +355,7 @@ +  + 	host->cmd = cmd; +  +-	/* Not sure if this is needed */ +-#if 0 ++	/* Needed for leaving busy state before CMD1 */ + 	if ((at91_mci_read(host, AT91_MCI_SR) & AT91_MCI_RTOE) && (cmd->opcode == 1)) { + 		pr_debug("Clearing timeout\n"); + 		at91_mci_write(host, AT91_MCI_ARGR, 0); +@@ -383,7 +365,7 @@ + 			pr_debug("Clearing: SR = %08X\n", at91_mci_read(host, AT91_MCI_SR)); + 		} + 	} +-#endif ++ + 	cmdr = cmd->opcode; +  + 	if (mmc_resp_type(cmd) == MMC_RSP_NONE) +@@ -440,50 +422,48 @@ + 		at91_mci_write(host, ATMEL_PDC_TCR, 0); + 		at91_mci_write(host, ATMEL_PDC_TNPR, 0); + 		at91_mci_write(host, ATMEL_PDC_TNCR, 0); ++		ier = AT91_MCI_CMDRDY; ++	} else { ++		/* zero block length in PDC mode */ ++		mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff; ++		at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); ++ ++		/* ++		 * Disable the PDC controller ++		 */ ++		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); +  +-		at91_mci_write(host, AT91_MCI_ARGR, cmd->arg); +-		at91_mci_write(host, AT91_MCI_CMDR, cmdr); +-		return AT91_MCI_CMDRDY; +-	} +- +-	mr = at91_mci_read(host, AT91_MCI_MR) & 0x7fff;	/* zero block length and PDC mode */ +-	at91_mci_write(host, AT91_MCI_MR, mr | (block_length << 16) | AT91_MCI_PDCMODE); +- +-	/* +-	 * Disable the PDC controller +-	 */ +-	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); +- +-	if (cmdr & AT91_MCI_TRCMD_START) { +-		data->bytes_xfered = 0; +-		host->transfer_index = 0; +-		host->in_use_index = 0; +-		if (cmdr & AT91_MCI_TRDIR) { +-			/* +-			 * Handle a read +-			 */ +-			host->buffer = NULL; +-			host->total_length = 0; ++		if (cmdr & AT91_MCI_TRCMD_START) { ++			data->bytes_xfered = 0; ++			host->transfer_index = 0; ++			host->in_use_index = 0; ++			if (cmdr & AT91_MCI_TRDIR) { ++				/* ++				 * Handle a read ++				 */ ++				host->buffer = NULL; ++				host->total_length = 0; +  +-			at91mci_pre_dma_read(host); +-			ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; +-		} +-		else { +-			/* +-			 * Handle a write +-			 */ +-			host->total_length = block_length * blocks; +-			host->buffer = dma_alloc_coherent(NULL, +-						  host->total_length, +-						  &host->physical_address, GFP_KERNEL); +- +-			at91mci_sg_to_dma(host, data); +- +-			pr_debug("Transmitting %d bytes\n", host->total_length); +- +-			at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); +-			at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4); +-			ier = AT91_MCI_TXBUFE; ++				at91_mci_pre_dma_read(host); ++				ier = AT91_MCI_ENDRX /* | AT91_MCI_RXBUFF */; ++			} ++			else { ++				/* ++			 	* Handle a write ++			 	*/ ++				host->total_length = block_length * blocks; ++				host->buffer = dma_alloc_coherent(NULL, ++							host->total_length, ++							&host->physical_address, GFP_KERNEL); ++ ++				at91_mci_sg_to_dma(host, data); ++ ++				pr_debug("Transmitting %d bytes\n", host->total_length); ++ ++				at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address); ++				at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4); ++				ier = AT91_MCI_CMDRDY; ++			} + 		} + 	} +  +@@ -498,39 +478,24 @@ + 	if (cmdr & AT91_MCI_TRCMD_START) { + 		if (cmdr & AT91_MCI_TRDIR) + 			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN); +-		else +-			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); + 	} +-	return ier; +-} +  +-/* +- * Wait for a command to complete +- */ +-static void at91mci_process_command(struct at91mci_host *host, struct mmc_command *cmd) +-{ +-	unsigned int ier; +- +-	ier = at91_mci_send_command(host, cmd); +- +-	pr_debug("setting ier to %08X\n", ier); +- +-	/* Stop on errors or the required value */ ++	/* Enable selected interrupts */ + 	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_ERRORS | ier); + } +  + /* +  * Process the next step in the request +  */ +-static void at91mci_process_next(struct at91mci_host *host) ++static void at91_mci_process_next(struct at91mci_host *host) + { + 	if (!(host->flags & FL_SENT_COMMAND)) { + 		host->flags |= FL_SENT_COMMAND; +-		at91mci_process_command(host, host->request->cmd); ++		at91_mci_send_command(host, host->request->cmd); + 	} + 	else if ((!(host->flags & FL_SENT_STOP)) && host->request->stop) { + 		host->flags |= FL_SENT_STOP; +-		at91mci_process_command(host, host->request->stop); ++		at91_mci_send_command(host, host->request->stop); + 	} + 	else + 		mmc_request_done(host->mmc, host->request); +@@ -539,7 +504,7 @@ + /* +  * Handle a command that has been completed +  */ +-static void at91mci_completed_command(struct at91mci_host *host) ++static void at91_mci_completed_command(struct at91mci_host *host) + { + 	struct mmc_command *cmd = host->cmd; + 	unsigned int status; +@@ -583,7 +548,7 @@ + 	else + 		cmd->error = MMC_ERR_NONE; +  +-	at91mci_process_next(host); ++	at91_mci_process_next(host); + } +  + /* +@@ -595,7 +560,60 @@ + 	host->request = mrq; + 	host->flags = 0; +  +-	at91mci_process_next(host); ++	at91_mci_process_next(host); ++} ++ ++/* ++ * Handle transmitted data ++ */ ++static void at91_mci_handle_transmitted(struct at91mci_host *host) ++{ ++	struct mmc_command *cmd; ++	struct mmc_data *data; ++ ++	pr_debug("Handling the transmit\n"); ++ ++	/* Disable the transfer */ ++	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); ++ ++	/* Now wait for cmd ready */ ++	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE); ++ ++	cmd = host->cmd; ++	if (!cmd) return; ++ ++	data = cmd->data; ++	if (!data) return; ++ ++	if (cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) { ++		pr_debug("multiple write : wait for BLKE...\n"); ++		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); ++	} else ++		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); ++ ++	data->bytes_xfered = host->total_length; ++} ++ ++ ++/*Handle after command sent ready*/ ++static int at91_mci_handle_cmdrdy(struct at91mci_host *host) ++{ ++	if (!host->cmd) ++		return 1; ++	else if (!host->cmd->data) { ++		if (host->flags & FL_SENT_STOP) { ++			/*After multi block write, we mus wait for NOTBUSY*/ ++			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY); ++		} else return 1; ++	} else if (host->cmd->data->flags & MMC_DATA_WRITE) { ++		/*After sending multi-block-write command, start DMA transfer*/ ++		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_TXBUFE); ++		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_BLKE); ++		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN); ++	} ++ ++	/* command not completed, have to wait */ ++	return 0; + } +  + /* +@@ -698,29 +716,33 @@ + 			at91_mci_handle_transmitted(host); + 		} +  ++		if (int_status & AT91_MCI_ENDRX) { ++			pr_debug("ENDRX\n"); ++			at91_mci_post_dma_read(host); ++		} ++ + 		if (int_status & AT91_MCI_RXBUFF) { + 			pr_debug("RX buffer full\n"); +-			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); ++			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS); ++			at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_RXBUFF | AT91_MCI_ENDRX); ++			completed = 1; + 		} +  + 		if (int_status & AT91_MCI_ENDTX) + 			pr_debug("Transmit has ended\n"); +  +-		if (int_status & AT91_MCI_ENDRX) { +-			pr_debug("Receive has ended\n"); +-			at91mci_post_dma_read(host); +-		} +- + 		if (int_status & AT91_MCI_NOTBUSY) { + 			pr_debug("Card is ready\n"); +-			at91_mci_write(host, AT91_MCI_IER, AT91_MCI_CMDRDY); ++			completed = 1; + 		} +  + 		if (int_status & AT91_MCI_DTIP) + 			pr_debug("Data transfer in progress\n"); +  +-		if (int_status & AT91_MCI_BLKE) ++		if (int_status & AT91_MCI_BLKE) { + 			pr_debug("Block transfer has ended\n"); ++			completed = 1; ++		} +  + 		if (int_status & AT91_MCI_TXRDY) + 			pr_debug("Ready to transmit\n"); +@@ -730,14 +752,14 @@ +  + 		if (int_status & AT91_MCI_CMDRDY) { + 			pr_debug("Command ready\n"); +-			completed = 1; ++			completed = at91_mci_handle_cmdrdy(host); + 		} + 	} +  + 	if (completed) { + 		pr_debug("Completed command\n"); + 		at91_mci_write(host, AT91_MCI_IDR, 0xffffffff); +-		at91mci_completed_command(host); ++		at91_mci_completed_command(host); + 	} else + 		at91_mci_write(host, AT91_MCI_IDR, int_status); +  diff --git a/target/linux/at91-2.6/patches/013-at91-mmc1wire.patch b/target/linux/at91-2.6/patches/013-at91-mmc1wire.patch new file mode 100644 index 000000000..31b1e9677 --- /dev/null +++ b/target/linux/at91-2.6/patches/013-at91-mmc1wire.patch @@ -0,0 +1,12 @@ +--- linux-2.6.21.1.old/drivers/mmc/at91_mci.c	2007-06-05 11:08:39.000000000 +0200 ++++ linux-2.6.21.1/drivers/mmc/at91_mci.c	2007-06-05 11:28:40.000000000 +0200 +@@ -79,8 +79,7 @@ +  + #define DRIVER_NAME "at91_mci" +  +-//#undef	SUPPORT_4WIRE +-#define 	SUPPORT_4WIRE ++#undef	SUPPORT_4WIRE +  + #define FL_SENT_COMMAND	(1 << 0) + #define FL_SENT_STOP	(1 << 1)  | 
