Subject: Re: Bestcomm tasks and interrupts on MPC5200(B)

From: Frank Bennett <[email-masked]>
Date: Tue, 20 Jan 2009 08:59:46 -0700

Dave Best wrote:
> I'm trying to write a driver which uses the Local Plus Bus on my MPC5200B and therefore have to use BestComm DMA, which requires me to use a Gen_BD task for data transfer with Local Plus.
> I tried to follow the fec driver that is currently used and took a peek at the mpc52xx-ac97 driver which at least uses the same kind of bus as I.
>
> Initialising the task, resetting and enabling works fine. Even request_irq reports no error, but when I start a transfer it hangs and if I am lucky, an interrupt occurs after quite some time. But it's always the BestComm ethernet rx task which produces an RFIFO interrupt, presumably after the watchdog catches on. 
> If this happens my interrupt occurs to.
>
> I tried to debug this situation but I am still clueless.
> If I use the MPC5200 Interrupt emulation registers to force an interrupt for my interface to occur, nothing happens except that it hangs.
>
> Any hints, tips or help appreciated.
>   
Below is a Disassembler I wrote a couple years ago. Just paste
the hex of interest in the array below, re-compile and run.

Cheers,
-Frank
> Dave
>
>
>       
> _______________________________________________
> Linuxppc-dev mailing list
> [email-masked]
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>   

/*
 * disasm.c - disassembler for MPC5200 Bestcomm DMA Firmware
 *            copy and paste task code into fw, compile a run
 * by Frank bennett, 3/29/2006
 *
 * Based on Freescale pdf "SmartDMA Hand-Assembly Guides"
 *
 * TODO:
 *  o add inc[0:7] array (maybe var) to deternmine proper term condition (upper 3 bits)
 *  o need to review sheet 3 of the pdf
 *  o simulator would be nice
 *
 */
// Task12 (TASK_GEN_TX_BD) : Start of TDT -> 0xf0008528
// linuxppc_2_4_devel/arch/ppc/5xxx_io/bestcomm/code_dma/image_rtos1/"dma_image.reloc.c
//
// 31,30,29,28|27,26,25,24|23,22,21,20|19,18,17,16|15,14,13,12|11,10, 9, 8| 7, 6, 5, 4| 3, 2, 1, 0
//  0  0  0  1  0  0| 0  0  0  0  0| 0  0| 0  0| 0| 0  0  0  1  0  0| 1| 1  0  0  0  0  1| 0  0  0
// 0x10001308, /* 000C      DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=2 */
//  1  0  0| 1  1  0  0  1  0| 0| 0| 1  1  0  0  1  0| 0  0| 0| 0  0  0  0  0  0| 1  1  0| 1  1  0
// 0x99190036, /* 002C    LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */
// 31,30,29,28|27,26,25,24|23,22,21,20|19,18,17,16|15,14,13,12|11,10, 9, 8| 7, 6, 5, 4| 3, 2, 1, 0
// 1   0| 0  1  1  0, 0  1  0  1,    1  0  0, 0  0  1| 1  0| 1  0  0  1  0  0  0  0  1  0  0  0  0
// 0x9950d210

/* Task12(TASK_GEN_TX_BD): Start of TDT -> 0xf0008528 */
unsigned long fw[] = {
    0x800220e3, /* 0000  LCD: idx0 = var0, idx1 = var4; idx1 <= var3; idx0 += inc4, idx1 += inc3 */
    0x13e01010, /* 0004    DRD1A: var4 = var2; FN=0 MORE init=24 WS=0 RS=0 */
    0xb8808264, /* 0008    LCD: idx2 = *idx1, idx3 = var1; idx2 < var9; idx2 += inc4, idx3 += inc4 */
    0x10001308, /* 000C      DRD1A: var4 = idx1; FN=0 MORE init=0 WS=0 RS=2 */
    0x60140002, /* 0010      DRD2A: EU0=0 EU1=0 EU2=0 EU3=2 EXT init=0 WS=2 RS=2 */
    0x0cccfcca, /* 0014      DRD2B1: *idx3 = EU3(); EU3(*idx3,var10)  */
    0xd9190300, /* 0018    LCDEXT: idx2 = idx2; idx2 > var12; idx2 += inc0 */
    0xb8c5e009, /* 001C    LCD: idx3 = *(idx1 + var00000015); ; idx3 += inc1 */
    0x03fec398, /* 0020      DRD1A: *idx0 = *idx3; FN=0 init=24 WS=3 RS=2 */
    0x9919826a, /* 0024    LCD: idx2 = idx2, idx3 = idx3; idx2 > var9; idx2 += inc5, idx3 += inc2 */
    0x0feac398, /* 0028      DRD1A: *idx0 = *idx3; FN=0 TFD INT init=24 WS=1 RS=2 */
    0x99190036, /* 002C    LCD: idx2 = idx2; idx2 once var0; idx2 += inc6 */
    0x60000005, /* 0030      DRD2A: EU0=0 EU1=0 EU2=0 EU3=5 EXT init=0 WS=0 RS=0 */
    0x0c4cf889, /* 0034      DRD2B1: *idx1 = EU3(); EU3(idx2,var9)  */
    0x000001f8, /* 0038    NOP */
    0x9950d210,
	0x2c4cf889,
    0
};

union
{
    unsigned long i;
    struct
    {
        unsigned sb:3;     // [02:00] increment #2
        unsigned sa:3;     // [05:03] increment #1
        unsigned tc:6;     // [11:06] variable to which idx is compared   
        unsigned drtc:1;   //    [12] dr ? *(tc) : (tc)
        unsigned tu:2;     // [14:13] term usage 00-idx_a, 01-idx_b, 10- lit init 11-no cond
        unsigned ib:6;     // [20:15] init_b 
        unsigned drib:1;   //    [21] dr ? *(init_a) : (init_a)
        unsigned p:1;      //    [22] indx plus offset
        unsigned ia:6;     // [28:23] init_a 
        unsigned dria:1;   //    [29] dr ? *(init_a) : (init_a)
        unsigned ext:1;    //    [30] = 2 or 3 for LCD
        unsigned op:1;     //    [31] = 2 or 3 for LCD
    } lcd;
    struct
    {
        unsigned ll:13;    // [12:00] literal init low
        unsigned tu:2;     // [14:13] term usage == 2
        unsigned lh:15;    // [29:15] literal init hi 
        unsigned bas:1;    //    [30] = 2 or 3 for LCD
        unsigned op:1;     //    [31] = 2 or 3 for LCD
    } lcdl;

    struct
    {
        unsigned fn:3;     // [02:00]
        unsigned src:6;    // [08:03]
        unsigned drs:1;    //    [09] deref src?
        unsigned dst:6;    // [15:10]
        unsigned drd:1;    //    [16] deref dst? scal?
        unsigned ws:2;     // [18:17] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned rs:2;     // [20:19] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned init:5;   // [25:21]
        unsigned intr:1;   //    [26]
        unsigned tfd:1;    //    [27]
        unsigned more:1;   //    [28]      
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd1a;
    struct
    {
        unsigned eu3:4;    // [03:00] Execution Unit3 Function number
        unsigned eu2:4;    // [07:04] Execution Unit3 Function number
        unsigned eu1:4;    // [11:08] Execution Unit3 Function number
        unsigned eu0:4;    // [15:12] Execution Unit3 Function number
        unsigned drd:1;    //    [16] deref dst? scal?
        unsigned ws:2;     // [18:17] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned rs:2;     // [20:19] 0-32bit, 1-1 byte, 2-16 word, 3-dynamic/reserved??
        unsigned init:5;   // [25:21]
        unsigned int:1;    //    [26]
        unsigned tfd:1;    //    [27]
        unsigned more:1;   //    [28]      
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd2a;
    struct
    {
        unsigned od1:6;    // [05:00] EU operand 1
        unsigned od0:6;    // [11:06] EU operand 0
        unsigned eu:2;     // [13:12] EU#, only #3 available on MPC5200
        unsigned mems:6;   // [19:14] memory write source
        unsigned drds:1;   //    [20]      
        unsigned rsv2:1;   //    [21]      
        unsigned memd:6;   // [27:22] memory write destination
        unsigned rsv1:1;   //    [28] reserved?
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd2b1;
    struct
    {
        unsigned odb1:6;   // [05:00] EUb operand 1/3/5/7
        unsigned odb0:6;   // [11:06] EUb operand 0/2/4/6
        unsigned eub:2;    // [13:12] EUb#, only #3 available on MPC5200
        unsigned oda1:6;   // [19:14] EUa operand 1/3/5/7
        unsigned oda0:6;   // [25:20] EUa operand 0/2/4/6
        unsigned eua:2;    // [27:26] EUa#, only #3 available on MPC5200
        unsigned rsv1:1;   //    [28]      
        unsigned type:1;   //    [29] 
        unsigned ext:1;    //    [30] 
        unsigned op:1;     //    [31] = 0 for DRD
    } drd2b2;
} x;

// Condition codes (first 4 bits of the increments)
// >=   c
// >    4
// once 0
// !=   6
// <=   a
// <    2

char *ft[] = {
    "ld_acc", "unld_acc", "and", "or", "xor" "andn", "not",
    "add", "sub", "lsh", "rsh", "crc8", "crc16", "crc32", 
	"endian32", "endian16"
};

char s[8];
indvar (int i)
{
    switch ((i & 0x3f) >> 4)
    {
    case 0:
        sprintf (s, "var%d", i & 0x1f); // varN
        break;
    case 1:
        sprintf (s, "inc%d", i & 0x07); // incN
        break;
    case 2:    			                // extraN
    case 3:
        sprintf (s, "idx%d", i & 0x0f); // idxN
        break;
    }
}

#define L2 LLev*2
main ()
{
    int i, j, LLev = 0, drdt, ex = 0, ml;
    char in[12];

    for (i = 0; fw[i]; i++)
    {
        x.i = fw[i];
        if (x.i == 0x1f8)
            printf ("0x%08x, // NOP\n", x.i);
        else if (x.lcd.op)      	// LCD
        {
            if (LLev == 0)
                strcpy (in, "");
            else
                strcpy (in, "  ");

            if (x.lcd.ext)			// LCDEXT
            {
                indvar (x.lcd.tc);
                printf
                    ("0x%08x, // %sLCDEXT: idx%d=idx%d; idx%d >%s%s ; idx%d += inc%d\n",
                     x.i, in, L2, L2, L2, x.lcd.drtc ? "*" : " ", s, L2,
                     x.lcd.sb);
            } else if (x.lcd.tu == 2)	 // LCDLIT
            {
                printf ("0x%08x, // %sLCDLIT: idx%d = 0x%07x ??\n",
                        x.i, in, L2, (x.lcdl.lh << 13) | x.lcdl.ll);
            } else                	// LCD
            {
                printf ("0x%08x, // %sLCD: ", x.i, in);
                if (x.lcd.p)    // indexed p-plus
                {
                    indvar (x.lcd.ia);
                    printf ("idx%d = %s(%s + ", L2 + 1, x.lcd.dria ? "*" : " ", s);
                    indvar (x.lcd.ib);
                    printf ("%s%s); ; ", x.lcd.drib ? "*" : " ", s);
                } else
                {
                    indvar (x.lcd.ia);
                    printf ("idx%d=%s%s, ", L2, x.lcd.dria ? "*" : " ", s);
                    indvar (x.lcd.ib);
                    printf ("idx%d=%s%s, ", L2 + 1, x.lcd.drib ? "*" : " ", s);
                }
                if (x.lcd.tu < 2)
                {
                    indvar (x.lcd.tc);
                    printf ("idx%d <=%s%s, ", (x.lcd.tu == 0) ? L2 : L2 + 1,
                            x.lcd.drtc ? "*" : " ", s);
                }
                if (x.lcd.tu != 3)
                    printf ("idx%d += inc%01x, ", L2, x.lcd.sa);
                printf ("idx%d += inc%01x\n", L2 + 1, x.lcd.sb);
                ex = 0;
            }
        }
        else
        {
            // DRD
            if (LLev == 0)
                strcpy (in, "  ");
            else
                strcpy (in, "    ");
            drdt = (ex << 2) | (x.drd1a.ext << 1) | x.drd1a.type;
            switch (drdt)
            {
            case 0:            // DRD1A
                printf ("0x%08x, // %sDRD1A: ", x.i, in);
                indvar (x.drd1a.dst);
                printf ("%s%s =", x.drd1a.drd ? "*" : " ", s);
                indvar (x.drd1a.src);
                printf ("%s%s; ", x.drd1a.drs ? "*" : " ", s);
                printf ("FN=%d (%s) ", x.drd1a.fn, ft[x.drd1a.fn]);
                if (x.drd1a.more)
                    printf ("MORE ");
                if (x.drd1a.tfd)
                    printf ("TFD ");
                if (x.drd1a.intr)
                    printf ("INT ");
                printf ("init=%d ", x.drd1a.init);
                printf ("WS=%d RS=%d \n", x.drd1a.ws, x.drd1a.rs);
                break;
            case 3:            // DRD2A
                ex = x.drd2a.ext;
                printf ("0x%08x, // %sDRD2A: ", x.i, in);
                printf ("EU0=0 EU1=0 EU2=0 EU3=%d (%s) EXT init=%d ",
                        x.drd2a.eu3, ft[x.drd2a.eu3], x.drd2a.init);
                printf ("WS=%d RS=%d \n", x.drd2a.ws, x.drd2a.rs);
                break;
            case 4:            // DRD2B1
                printf ("0x%08x, // %sDRD2B1: ", x.i, in);
                indvar (x.drd2b1.memd);   // mems ??
                printf ("*%s=EU%d(); ", s, x.drd2b1.eu);
                indvar (x.drd2b1.od0); printf ("EU%d(%s, ", x.drd2b1.eu, s);
                indvar (x.drd2b1.od1); printf ("%s) \n", s);
                break;
            case 5:            // DRD2B2
            case 7:            // DRD2B2?
                printf ("0x%08x, // %sDRD2B2: ", x.i, in);
                indvar (x.drd2b2.oda0); printf ("EU%d(%s, ", x.drd2b2.eub, s);
                indvar (x.drd2b2.oda1); printf ("%s) , ", s);
                indvar (x.drd2b2.odb0); printf ("EU%d(%s, ", x.drd2b2.eua, s);
                indvar (x.drd2b2.odb1); printf ("%s) ??\n", s);
				break;
            case 1:
            case 2:
            case 6:
                printf ("fix_me\n");
                ex = x.drd1a.ext;
                break;
            }
            LLev |= 1;
        }
    }
}