SPI controller hangs in 2.6 and not in 2.4

Greg Lopp lopp at pobox.com
Tue Feb 27 03:43:13 EST 2007


I see that your code enables interrupts in the CPM and sets BD_SC_INTRPT,
but you do not claim the IRQ anywhere in this sample.

It doesn't explain the 2.4 vs 2.6 issues, but where is the request_irq() ?


On 2/25/07, DI BACCO ANTONIO - technolabs <Antonio.DiBacco at technolabs.it>
wrote:
>
>  Hi all,
>
> strange problem with SPI 8xx controller. I attach a litte code snippet
> that I use to produce the hang, just when giving the start command to the
> controller, the kernel hangs. START command is given in transmit_data called
> directly in init.
>
> #include <linux/init.h>
> #include <linux/module.h>
> #include <linux/kernel.h>
>
> #include <linux/delay.h>               // for udelay()
> #include <linux/interrupt.h>
> #include <asm/io.h>
> #include <asm/semaphore.h>
>
> #include <asm/commproc.h>
> #include <linux/ioport.h>       // for request_mem_region
> #include <asm/irq.h>            // for SIU_IRQ1
>
> #define SPI_MAX_BUFFER_SIZE     8
> #define BD_SC_ME        ((ushort)0x0001)    /* Multi Master Error */
> #define SPCOM_STR             0x80    /* Start transmission command */
>
>
> volatile car8xx_t       *carp;
> volatile spi_t          *spi;
> volatile immap_t        *immap;
> volatile cpic8xx_t      *cpi;
> volatile cpm8xx_t       *cp;
> volatile iop8xx_t       *iop;
>
> static cbd_t *tbdf, *rbdf;
>
> static u8* txbuffer;
> static u8* rxbuffer;
> static u16 r_tbase, r_rbase;
> u8 txbuf[32];
> u8 rxbuf[32];
>
> static int transmit_data()
> {
>    int result = 0;  // default is no error
>
>    // BD status/control register
>    tbdf->cbd_sc = BD_SC_READY | BD_SC_WRAP | BD_SC_LAST;
>    rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP | BD_SC_INTRPT;
>
>    cp->cp_spmode = 0x0778 | SPMODE_LOOP;                   // spi mode
> setting
>    cp->cp_spmode |= 0x0100;                // enable SPI
>    cp->cp_spie   = 0xff;                   // clear all spi events
>    cp->cp_spim   = 0x37;                   // mask all SPI events
>
>    udelay(5); // Wait 5 microsecs
>
>    cp->cp_spcom = SPCOM_STR;   // start the transfer
>
>    printk("after spcom\n");
>    udelay(100);
>    // go on and clear chip select befor looking at the result
>
>    // wait 2 character times before writing to SPI bus again !!! ?????
>
>    cp->cp_spmode = 0x00;   // reset spi mode
>
>
>    // test receive and transmit buffer descriptor for errors
>    if (rbdf->cbd_sc & (BD_SC_EMPTY | BD_SC_OV | BD_SC_ME))
>    {
>            result = -EIO;
>    }
>    if (tbdf->cbd_sc & (BD_SC_READY | BD_SC_UN | BD_SC_ME))
>    {
>            result = -EIO;
>    }
>
>         return result;
> } // int transmit_data
>
>
> static int hello_init(void)
> {
>         u32 dp_addr;
>         // get pointer to processors internal memory map
>         immap = (immap_t *)IMAP_ADDR;
>         //  printk("*** spi_read: immap = 0x%08x ***\n",(unsigned
> int)immap);
>
>         // get pointer to cpm interrupt controller
>         cpi = (cpic8xx_t*)&(((volatile immap_t*)IMAP_ADDR)->im_cpic);
>         //  printk("*** spi_read: cpi = 0x%08x ***\n",(unsigned int)cpi);
>
>         // get pointer to input/output port
>         iop = (iop8xx_t *)&(((volatile immap_t *)IMAP_ADDR)->im_ioport);
>         //  printk("*** spi_read: iop = 0x%08x ***\n",(unsigned int)iop);
>
>         // get pointer to communication processor
>         cp = (cpm8xx_t *)&(((volatile immap_t *)IMAP_ADDR)->im_cpm);
>         //  printk("*** spi_init: cp = 0x%08x ***\n",(unsigned int)cp);
>
>         // get pointer to Serial Peripheral Interface parameter RAM
>         spi = (spi_t *)&cp->cp_dparam[PROFF_SPI];
>         //  printk("*** spi_init: spi = 0x%08x ***\n",(unsigned int)spi);
>
>         // get pointer to clocks and reset
>         carp = (car8xx_t *)&((volatile immap_t *)IMAP_ADDR)->im_clkrst;
>         //  printk("*** spi_init: carp = 0x%08x ***\n",(unsigned
> int)carp);
>
>         // ------------------------------------------
>         //  SCCR[DFBRG] = 0  -->  BRGCLK = vcoout/1          ### verwenden
> nicht auch andere in ioDriver ????
>         // ------------------------------------------
>         carp->car_sccr &= 0xFFFFE7FF;
>
>         //  initialize the parameter ram
>         //  we need to make sure many things are initialized to zero
>         spi->spi_rstate = 0;
>         spi->spi_rdp = 0;
>         spi->spi_rbptr = 0;
>         spi->spi_rbc = 0;
>         spi->spi_rxtmp = 0;
>         spi->spi_tstate = 0;
>         spi->spi_tdp = 0;
>         spi->spi_tbptr = 0;
>         spi->spi_tbc = 0;
>         spi->spi_txtmp = 0;
>
>         // allocate space for one transmit and one receive buffer
> descriptor in the DP ram
>         dp_addr = cpm_dpalloc(sizeof(cbd_t) * 2, 8);
>         // printk("*** spi_init: dp_addr = 0x%08x ***\n",(unsigned
> int)dp_addr);
>
>         // Set up the SPI parameters in the parameter ram
>         spi->spi_rbase = r_rbase = dp_addr;
>         spi->spi_tbase = r_tbase = dp_addr + sizeof(cbd_t);
>
>         // ***********IMPORTANT******************
>         // setting transmit and receive buffer descriptor
>         // pointers initially to rbase and tbase. Only the
>         // microcode patches documentation talks about initializing
>         // this pointer. This is missing from the sample I2C driver.
>         // If you dont initialize these pointers, the kernel hangs.
>         spi->spi_rbptr = spi->spi_rbase;
>         spi->spi_tbptr = spi->spi_tbase;
>
>         // Set to big endian
>         spi->spi_tfcr = SMC_EB;
>         spi->spi_rfcr = SMC_EB;
>
>         spi->spi_mrblr = SPI_MAX_BUFFER_SIZE;    // Set maximum receive
> size
>         //  printk("*** spi_init: spi->spi_mrblr = 0x%04x
> ***\n",spi->spi_mrblr);
>
>         cp->cp_cpcr |= 0x51;    // Setting CPCR
>
>         immap->im_siu_conf.sc_sdcr = 0x0001;    // sets SDMA configuration
> register
>         cpi->cpic_cicr |= 0x00000580;           // enable cpm interrupts,
> spi has highest priority
>         cpi->cpic_cimr |= 0x00000020;           // enable spi interrupts
>
>         cp->cp_spie = 0xff;     // clear all spi events
>
>         //  printk("*** spi_init: iop->iop_pcdat = 0x%04x ***\n",
> iop->iop_pcdat);
>
>         // ------------------------------------------------
>         // initialize Port B SPI pins -> page 34-8 MPC860UM
>         // (we are only in master mode !)
>         // ------------------------------------------------
>
>         // --------------------------------------------
>         // GPIO or per. function
>         // PBPAR[28] = 1  -> PERI: (SPIMISO)
>         // PBPAR[29] = 1  -> PERI: (SPIMOSI)
>         // PBPAR[30] = 1  -> PERI: (SPICLK)
>         // --------------------------------------------
>         cp->cp_pbpar |= 0x0000000E;  // set bits
>        //  printk("*** spi_init: cp->cp_pbpar\n
> ADR=0x%08x\n              VAL=0x%08x\n",(unsigned int)&cp->cp_pbpar,
> cp->cp_pbpar);
>
>         // ----------------------------------------------
>         // In/Out or per. function 0/1
>         // PBDIR[28] = 1  -> PERI1: SPIMISO
>         // PBDIR[29] = 1  -> PERI1: SPIMOSI
>         // PBDIR[30] = 1  -> PERI1: SPICLK
>         // ----------------------------------------------
>         cp->cp_pbdir |= 0x0000000E;
>         //printk("*** spi_init: cp->cp_pbdir\n
> ADR=0x%08x\n              VAL=0x%08x\n",(unsigned int)&cp->cp_pbdir,
> cp->cp_pbdir);
>
>         // -------------------------------------------------------------
>         // attention: PBODR is a 32-bit-register,
>         // but in the memory-map-struct it is handled as
>         // 16-bit-register because lower 16 bit are always 0
>         //
>         // open drain or active output
>         // PBODR[28] = 1  -> open drain: SPIMISO
>         // PBODR[29] = 0  -> active output SPIMOSI
>         // PBODR[30] = 0  -> active output: SPICLK
>         // -------------------------------------------------------------
>         //  printk("\n*** cp->cp_pbodr = 0x%08x ***\n",cp->cp_pbodr);
>         cp->cp_pbodr |= 0x0008;  // set bits
>         cp->cp_pbodr &= 0xFFF9;  // reset bits
>         //  printk("*** spi_init: cp->cp_pbodr\n
> ADR=0x%08x\n              VAL=0x%04x\n",(unsigned int)&cp->cp_pbodr,
> cp->cp_pbodr);
>
>         //  printk("*** spi_init: cp->cp_pbdat\n
> ADR=0x%08x\n              VAL=0x%08x\n",(unsigned int)&cp->cp_pbdat,
> cp->cp_pbdat);
>
>         // tx and rx buffer descriptors
>         tbdf = (cbd_t *)&cp->cp_dpmem[r_tbase];
>         rbdf = (cbd_t *)&cp->cp_dpmem[r_rbase];
>
>         // initialize tx and tx bd's
>         tbdf->cbd_sc &= ~BD_SC_READY;
>         rbdf->cbd_sc &= ~BD_SC_EMPTY;
>
>         // Allocate memory as required
>         rxbuffer = (u8*)m8xx_cpm_hostalloc(SPI_MAX_BUFFER_SIZE);  //
> Memory alloc for receive buffer
>         txbuffer = (u8*)m8xx_cpm_hostalloc(SPI_MAX_BUFFER_SIZE);  //
> Memory alloc for transmit buffer
>
>         // Set the bd's rx and tx buffer address pointers
>         rbdf->cbd_bufaddr = virt_to_bus((void
> *)rxbuffer);
>         tbdf->cbd_bufaddr = virt_to_bus((void *)txbuffer);
>
>
>         transmit_data();
>
>   return 0;
> }
>
>
> static void hello_exit(void)
> {
> }
>
> module_init(hello_init);
> module_exit(hello_exit);
>
> MODULE_LICENSE("Dual BSD/GPL");
>
> _______________________________________________
> Linuxppc-embedded mailing list
> Linuxppc-embedded at ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-embedded
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://ozlabs.org/pipermail/linuxppc-embedded/attachments/20070226/8f9ea792/attachment.htm 


More information about the Linuxppc-embedded mailing list