ppc4xx_dma sucks

The DMA generic handling code for ppc4xx is broken. This is apparently well known enough that nobody is relying upon it. I learned this the hard way when implementing DMA to/from NAND flash MTD devices. Here’s a handy hacker’s guide to doing it right. The key thing is to not rely on any of the generic routines and to do direct setup of the DMA engine for yourself. To configure channel 2 (numbers in brackets correspond to the datasheet):

mtdcr(DCRN_DMACR2, 0);
/* 1. Set the transfer width: */
mtdcr(DCRN_DMACR2, SET_DMA_PW(PW_8));
/* 2. Source Address: */
mtdcr(DCRN_DMASA2, source_address);
/* 2. Destination Address: */
mtdcr(DCRN_DMADA2, destination_address);
/* 3. Set Count: */
mtdcr(DCRN_DMACT2, len);
/* 4. Clear Status: */
mtdcr(DCRN_DMASR, DMA_CS2|DMA_TS2|DMA_CH2_ERR);
/* Source Increment: */
mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_SAI(0));
/* 5. Destination Increment: */
mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_DAI(1));
/* 5. Software memory-to-memory: */
mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_TM(TM_S_MM));
/* 5. Interrupt Enable: */
mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_CIE_ENABLE(1));
mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_PL(EXTERNAL_PERIPHERAL));
mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_ETD(1)); /* 1 req. */
mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_TCE(1)); /* 1 req. */

To display the configuration:

printk("DMA Configuration:\n\n");
printk("DCRN_DMACR2=0x%08x\n", mfdcr(DCRN_DMACR2));
printk("DCRN_DMASA2=0x%08x\n", mfdcr(DCRN_DMASA2));
printk("DCRN_DMADA2=0x%08x\n", mfdcr(DCRN_DMADA2));
printk("DCRN_DMACT2=0x%08x\n", mfdcr(DCRN_DMACT2));
printk("DCRN_DMASR=0x%08x\n", mfdcr(DCRN_DMASR));

To enable the operation:

mtdcr(DCRN_DMACR2, mfdcr(DCRN_DMACR2) | SET_DMA_CE_ENABLE(1)); /* 5. Channel enable */

Sit and wait on an completion and have the interrupt handler also do this:

mtdcr(DCRN_DMASR, DMA_CS2|DMA_TS2|DMA_CH2_ERR); /* zero status */

Apprently, there’s talk of a generic DMA abstraction, which would be nice. I’m keen to help out with that once I get back onto playing with 2.6 proper.

I spent a bit of time over the weekend tidying up odds and ends on the magazine and doing some other writing. I’ve received an advance on the book now (and figured out how to pay a dollar cheque into my bank – that was fun) and am officially writing. Not that I’ve gotten very far yet but the important thing is I’ve at least started trying to make some progress. I’ve also written a bunch of other stuff and started reading more Bill Bryson. I’ve developed a morning routine of having coffee, a pasty, reading a bit of my book and catching up with The Independent. That’s a quality newspaper. I was shocked yesterday to discover that as of January all offences will become arrestable under law (no matter how trivial) and today they’re doing a good job of bashing Blair over the 90 day terror detention crap.

Jon.

Leave a Reply