uboot/arch/powerpc/cpu/mpc8xx/spi.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2001 Navin Boppuri / Prashant Patel
   3 *      <nboppuri@trinetcommunication.com>,
   4 *      <pmpatel@trinetcommunication.com>
   5 * Copyright (c) 2001 Gerd Mennchen <Gerd.Mennchen@icn.siemens.de>
   6 * Copyright (c) 2001 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>.
   7 *
   8 * See file CREDITS for list of people who contributed to this
   9 * project.
  10 *
  11 * This program is free software; you can redistribute it and/or
  12 * modify it under the terms of the GNU General Public License as
  13 * published by the Free Software Foundation; either version 2 of
  14 * the License, or (at your option) any later version.
  15 *
  16 * This program is distributed in the hope that it will be useful,
  17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19 * GNU General Public License for more details.
  20 *
  21 * You should have received a copy of the GNU General Public License
  22 * along with this program; if not, write to the Free Software
  23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  24 * MA 02111-1307 USA
  25 */
  26
  27/*
  28 * MPC8xx CPM SPI interface.
  29 *
  30 * Parts of this code are probably not portable and/or specific to
  31 * the board which I used for the tests. Please send fixes/complaints
  32 * to wd@denx.de
  33 *
  34 */
  35
  36#include <common.h>
  37#include <mpc8xx.h>
  38#include <commproc.h>
  39#include <linux/ctype.h>
  40#include <malloc.h>
  41#include <post.h>
  42#include <serial.h>
  43
  44#if (defined(CONFIG_SPI)) || (CONFIG_POST & CONFIG_SYS_POST_SPI)
  45
  46/* Warning:
  47 * You cannot enable DEBUG for early system initalization, i. e. when
  48 * this driver is used to read environment parameters like "baudrate"
  49 * from EEPROM which are used to initialize the serial port which is
  50 * needed to print the debug messages...
  51 */
  52#undef  DEBUG
  53
  54#define SPI_EEPROM_WREN         0x06
  55#define SPI_EEPROM_RDSR         0x05
  56#define SPI_EEPROM_READ         0x03
  57#define SPI_EEPROM_WRITE        0x02
  58
  59/* ---------------------------------------------------------------
  60 * Offset for initial SPI buffers in DPRAM:
  61 * We need a 520 byte scratch DPRAM area to use at an early stage.
  62 * It is used between the two initialization calls (spi_init_f()
  63 * and spi_init_r()).
  64 * The value 0xb00 makes it far enough from the start of the data
  65 * area (as well as from the stack pointer).
  66 * --------------------------------------------------------------- */
  67#ifndef CONFIG_SYS_SPI_INIT_OFFSET
  68#define CONFIG_SYS_SPI_INIT_OFFSET      0xB00
  69#endif
  70
  71#ifdef  DEBUG
  72
  73#define DPRINT(a)       printf a;
  74/* -----------------------------------------------
  75 * Helper functions to peek into tx and rx buffers
  76 * ----------------------------------------------- */
  77static const char * const hex_digit = "0123456789ABCDEF";
  78
  79static char quickhex (int i)
  80{
  81        return hex_digit[i];
  82}
  83
  84static void memdump (void *pv, int num)
  85{
  86        int i;
  87        unsigned char *pc = (unsigned char *) pv;
  88
  89        for (i = 0; i < num; i++)
  90                printf ("%c%c ", quickhex (pc[i] >> 4), quickhex (pc[i] & 0x0f));
  91        printf ("\t");
  92        for (i = 0; i < num; i++)
  93                printf ("%c", isprint (pc[i]) ? pc[i] : '.');
  94        printf ("\n");
  95}
  96#else   /* !DEBUG */
  97
  98#define DPRINT(a)
  99
 100#endif  /* DEBUG */
 101
 102/* -------------------
 103 * Function prototypes
 104 * ------------------- */
 105void spi_init (void);
 106
 107ssize_t spi_read (uchar *, int, uchar *, int);
 108ssize_t spi_write (uchar *, int, uchar *, int);
 109ssize_t spi_xfer (size_t);
 110
 111/* -------------------
 112 * Variables
 113 * ------------------- */
 114
 115#define MAX_BUFFER      0x104
 116
 117/* ----------------------------------------------------------------------
 118 * Initially we place the RX and TX buffers at a fixed location in DPRAM!
 119 * ---------------------------------------------------------------------- */
 120static uchar *rxbuf =
 121  (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
 122                        [CONFIG_SYS_SPI_INIT_OFFSET];
 123static uchar *txbuf =
 124  (uchar *)&((cpm8xx_t *)&((immap_t *)CONFIG_SYS_IMMR)->im_cpm)->cp_dpmem
 125                        [CONFIG_SYS_SPI_INIT_OFFSET+MAX_BUFFER];
 126
 127/* **************************************************************************
 128 *
 129 *  Function:    spi_init_f
 130 *
 131 *  Description: Init SPI-Controller (ROM part)
 132 *
 133 *  return:      ---
 134 *
 135 * *********************************************************************** */
 136void spi_init_f (void)
 137{
 138        unsigned int dpaddr;
 139
 140        volatile spi_t *spi;
 141        volatile immap_t *immr;
 142        volatile cpm8xx_t *cp;
 143        volatile cbd_t *tbdf, *rbdf;
 144
 145        immr = (immap_t *)  CONFIG_SYS_IMMR;
 146        cp   = (cpm8xx_t *) &immr->im_cpm;
 147
 148#ifdef CONFIG_SYS_SPI_UCODE_PATCH
 149        spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
 150#else
 151        spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
 152        /* Disable relocation */
 153        spi->spi_rpbase = 0;
 154#endif
 155
 156/* 1 */
 157        /* ------------------------------------------------
 158         * Initialize Port B SPI pins -> page 34-8 MPC860UM
 159         * (we are only in Master Mode !)
 160         * ------------------------------------------------ */
 161
 162        /* --------------------------------------------
 163         * GPIO or per. Function
 164         * PBPAR[28] = 1 [0x00000008] -> PERI: (SPIMISO)
 165         * PBPAR[29] = 1 [0x00000004] -> PERI: (SPIMOSI)
 166         * PBPAR[30] = 1 [0x00000002] -> PERI: (SPICLK)
 167         * PBPAR[31] = 0 [0x00000001] -> GPIO: (CS for PCUE/CCM-EEPROM)
 168         * -------------------------------------------- */
 169        cp->cp_pbpar |=  0x0000000E;    /* set  bits    */
 170        cp->cp_pbpar &= ~0x00000001;    /* reset bit    */
 171
 172        /* ----------------------------------------------
 173         * In/Out or per. Function 0/1
 174         * PBDIR[28] = 1 [0x00000008] -> PERI1: SPIMISO
 175         * PBDIR[29] = 1 [0x00000004] -> PERI1: SPIMOSI
 176         * PBDIR[30] = 1 [0x00000002] -> PERI1: SPICLK
 177         * PBDIR[31] = 1 [0x00000001] -> GPIO OUT: CS for PCUE/CCM-EEPROM
 178         * ---------------------------------------------- */
 179        cp->cp_pbdir |= 0x0000000F;
 180
 181        /* ----------------------------------------------
 182         * open drain or active output
 183         * PBODR[28] = 1 [0x00000008] -> open drain: SPIMISO
 184         * PBODR[29] = 0 [0x00000004] -> active output SPIMOSI
 185         * PBODR[30] = 0 [0x00000002] -> active output: SPICLK
 186         * PBODR[31] = 0 [0x00000001] -> active output: GPIO OUT: CS for PCUE/CCM
 187         * ---------------------------------------------- */
 188
 189        cp->cp_pbodr |=  0x00000008;
 190        cp->cp_pbodr &= ~0x00000007;
 191
 192        /* Initialize the parameter ram.
 193         * We need to make sure many things are initialized to zero
 194         */
 195        spi->spi_rstate = 0;
 196        spi->spi_rdp    = 0;
 197        spi->spi_rbptr  = 0;
 198        spi->spi_rbc    = 0;
 199        spi->spi_rxtmp  = 0;
 200        spi->spi_tstate = 0;
 201        spi->spi_tdp    = 0;
 202        spi->spi_tbptr  = 0;
 203        spi->spi_tbc    = 0;
 204        spi->spi_txtmp  = 0;
 205
 206        /* Allocate space for one transmit and one receive buffer
 207         * descriptor in the DP ram
 208         */
 209#ifdef CONFIG_SYS_ALLOC_DPRAM
 210        dpaddr = dpram_alloc_align (sizeof(cbd_t)*2, 8);
 211#else
 212        dpaddr = CPM_SPI_BASE;
 213#endif
 214
 215/* 3 */
 216        /* Set up the SPI parameters in the parameter ram */
 217        spi->spi_rbase = dpaddr;
 218        spi->spi_tbase = dpaddr + sizeof (cbd_t);
 219
 220        /***********IMPORTANT******************/
 221
 222        /*
 223         * Setting transmit and receive buffer descriptor pointers
 224         * initially to rbase and tbase. Only the microcode patches
 225         * documentation talks about initializing this pointer. This
 226         * is missing from the sample I2C driver. If you dont
 227         * initialize these pointers, the kernel hangs.
 228         */
 229        spi->spi_rbptr = spi->spi_rbase;
 230        spi->spi_tbptr = spi->spi_tbase;
 231
 232/* 4 */
 233#ifdef CONFIG_SYS_SPI_UCODE_PATCH
 234        /*
 235         *  Initialize required parameters if using microcode patch.
 236         */
 237        spi->spi_rstate = 0;
 238        spi->spi_tstate = 0;
 239#else
 240        /* Init SPI Tx + Rx Parameters */
 241        while (cp->cp_cpcr & CPM_CR_FLG)
 242                ;
 243        cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SPI, CPM_CR_INIT_TRX) | CPM_CR_FLG;
 244        while (cp->cp_cpcr & CPM_CR_FLG)
 245                ;
 246#endif  /* CONFIG_SYS_SPI_UCODE_PATCH */
 247
 248/* 5 */
 249        /* Set SDMA configuration register */
 250        immr->im_siu_conf.sc_sdcr = 0x0001;
 251
 252/* 6 */
 253        /* Set to big endian. */
 254        spi->spi_tfcr = SMC_EB;
 255        spi->spi_rfcr = SMC_EB;
 256
 257/* 7 */
 258        /* Set maximum receive size. */
 259        spi->spi_mrblr = MAX_BUFFER;
 260
 261/* 8 + 9 */
 262        /* tx and rx buffer descriptors */
 263        tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
 264        rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
 265
 266        tbdf->cbd_sc &= ~BD_SC_READY;
 267        rbdf->cbd_sc &= ~BD_SC_EMPTY;
 268
 269        /* Set the bd's rx and tx buffer address pointers */
 270        rbdf->cbd_bufaddr = (ulong) rxbuf;
 271        tbdf->cbd_bufaddr = (ulong) txbuf;
 272
 273/* 10 + 11 */
 274        cp->cp_spim = 0;                        /* Mask  all SPI events */
 275        cp->cp_spie = SPI_EMASK;                /* Clear all SPI events */
 276
 277        return;
 278}
 279
 280/* **************************************************************************
 281 *
 282 *  Function:    spi_init_r
 283 *
 284 *  Description: Init SPI-Controller (RAM part) -
 285 *               The malloc engine is ready and we can move our buffers to
 286 *               normal RAM
 287 *
 288 *  return:      ---
 289 *
 290 * *********************************************************************** */
 291void spi_init_r (void)
 292{
 293        volatile cpm8xx_t *cp;
 294        volatile spi_t *spi;
 295        volatile immap_t *immr;
 296        volatile cbd_t *tbdf, *rbdf;
 297
 298        immr = (immap_t *)  CONFIG_SYS_IMMR;
 299        cp   = (cpm8xx_t *) &immr->im_cpm;
 300
 301#ifdef CONFIG_SYS_SPI_UCODE_PATCH
 302        spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
 303#else
 304        spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
 305        /* Disable relocation */
 306        spi->spi_rpbase = 0;
 307#endif
 308
 309        /* tx and rx buffer descriptors */
 310        tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
 311        rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
 312
 313        /* Allocate memory for RX and TX buffers */
 314        rxbuf = (uchar *) malloc (MAX_BUFFER);
 315        txbuf = (uchar *) malloc (MAX_BUFFER);
 316
 317        rbdf->cbd_bufaddr = (ulong) rxbuf;
 318        tbdf->cbd_bufaddr = (ulong) txbuf;
 319
 320        return;
 321}
 322
 323/****************************************************************************
 324 *  Function:    spi_write
 325 **************************************************************************** */
 326ssize_t spi_write (uchar *addr, int alen, uchar *buffer, int len)
 327{
 328        int i;
 329
 330        memset(rxbuf, 0, MAX_BUFFER);
 331        memset(txbuf, 0, MAX_BUFFER);
 332        *txbuf = SPI_EEPROM_WREN;               /* write enable         */
 333        spi_xfer(1);
 334        memcpy(txbuf, addr, alen);
 335        *txbuf = SPI_EEPROM_WRITE;              /* WRITE memory array   */
 336        memcpy(alen + txbuf, buffer, len);
 337        spi_xfer(alen + len);
 338                                                /* ignore received data */
 339        for (i = 0; i < 1000; i++) {
 340                *txbuf = SPI_EEPROM_RDSR;       /* read status          */
 341                txbuf[1] = 0;
 342                spi_xfer(2);
 343                if (!(rxbuf[1] & 1)) {
 344                        break;
 345                }
 346                udelay(1000);
 347        }
 348        if (i >= 1000) {
 349                printf ("*** spi_write: Time out while writing!\n");
 350        }
 351
 352        return len;
 353}
 354
 355/****************************************************************************
 356 *  Function:    spi_read
 357 **************************************************************************** */
 358ssize_t spi_read (uchar *addr, int alen, uchar *buffer, int len)
 359{
 360        memset(rxbuf, 0, MAX_BUFFER);
 361        memset(txbuf, 0, MAX_BUFFER);
 362        memcpy(txbuf, addr, alen);
 363        *txbuf = SPI_EEPROM_READ;               /* READ memory array    */
 364
 365        /*
 366         * There is a bug in 860T (?) that cuts the last byte of input
 367         * if we're reading into DPRAM. The solution we choose here is
 368         * to always read len+1 bytes (we have one extra byte at the
 369         * end of the buffer).
 370         */
 371        spi_xfer(alen + len + 1);
 372        memcpy(buffer, alen + rxbuf, len);
 373
 374        return len;
 375}
 376
 377/****************************************************************************
 378 *  Function:    spi_xfer
 379 **************************************************************************** */
 380ssize_t spi_xfer (size_t count)
 381{
 382        volatile immap_t *immr;
 383        volatile cpm8xx_t *cp;
 384        volatile spi_t *spi;
 385        cbd_t *tbdf, *rbdf;
 386        ushort loop;
 387        int tm;
 388
 389        DPRINT (("*** spi_xfer entered ***\n"));
 390
 391        immr = (immap_t *) CONFIG_SYS_IMMR;
 392        cp   = (cpm8xx_t *) &immr->im_cpm;
 393
 394#ifdef CONFIG_SYS_SPI_UCODE_PATCH
 395        spi  = (spi_t *)&cp->cp_dpmem[spi->spi_rpbase];
 396#else
 397        spi  = (spi_t *)&cp->cp_dparam[PROFF_SPI];
 398        /* Disable relocation */
 399        spi->spi_rpbase = 0;
 400#endif
 401
 402        tbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_tbase];
 403        rbdf = (cbd_t *) & cp->cp_dpmem[spi->spi_rbase];
 404
 405        /* Set CS for device */
 406        cp->cp_pbdat &= ~0x0001;
 407
 408        /* Setting tx bd status and data length */
 409        tbdf->cbd_sc  = BD_SC_READY | BD_SC_LAST | BD_SC_WRAP;
 410        tbdf->cbd_datlen = count;
 411
 412        DPRINT (("*** spi_xfer: Bytes to be xferred: %d ***\n",
 413                                                        tbdf->cbd_datlen));
 414
 415        /* Setting rx bd status and data length */
 416        rbdf->cbd_sc = BD_SC_EMPTY | BD_SC_WRAP;
 417        rbdf->cbd_datlen = 0;    /* rx length has no significance */
 418
 419        loop = cp->cp_spmode & SPMODE_LOOP;
 420        cp->cp_spmode = /*SPMODE_DIV16  |*/     /* BRG/16 mode not used here */
 421                        loop            |
 422                        SPMODE_REV      |
 423                        SPMODE_MSTR     |
 424                        SPMODE_EN       |
 425                        SPMODE_LEN(8)   |       /* 8 Bits per char */
 426                        SPMODE_PM(0x8) ;        /* medium speed */
 427        cp->cp_spim = 0;                        /* Mask  all SPI events */
 428        cp->cp_spie = SPI_EMASK;                /* Clear all SPI events */
 429
 430        /* start spi transfer */
 431        DPRINT (("*** spi_xfer: Performing transfer ...\n"));
 432        cp->cp_spcom |= SPI_STR;                /* Start transmit */
 433
 434        /* --------------------------------
 435         * Wait for SPI transmit to get out
 436         * or time out (1 second = 1000 ms)
 437         * -------------------------------- */
 438        for (tm=0; tm<1000; ++tm) {
 439                if (cp->cp_spie & SPI_TXB) {    /* Tx Buffer Empty */
 440                        DPRINT (("*** spi_xfer: Tx buffer empty\n"));
 441                        break;
 442                }
 443                if ((tbdf->cbd_sc & BD_SC_READY) == 0) {
 444                        DPRINT (("*** spi_xfer: Tx BD done\n"));
 445                        break;
 446                }
 447                udelay (1000);
 448        }
 449        if (tm >= 1000) {
 450                printf ("*** spi_xfer: Time out while xferring to/from SPI!\n");
 451        }
 452        DPRINT (("*** spi_xfer: ... transfer ended\n"));
 453
 454#ifdef  DEBUG
 455        printf ("\nspi_xfer: txbuf after xfer\n");
 456        memdump ((void *) txbuf, 16);   /* dump of txbuf before transmit */
 457        printf ("spi_xfer: rxbuf after xfer\n");
 458        memdump ((void *) rxbuf, 16);   /* dump of rxbuf after transmit */
 459        printf ("\n");
 460#endif
 461
 462        /* Clear CS for device */
 463        cp->cp_pbdat |= 0x0001;
 464
 465        return count;
 466}
 467#endif  /* CONFIG_SPI || (CONFIG_POST & CONFIG_SYS_POST_SPI) */
 468
 469/*
 470 * SPI test
 471 *
 472 * The Serial Peripheral Interface (SPI) is tested in the local loopback mode.
 473 * The interface is configured accordingly and several packets
 474 * are transfered. The configurable test parameters are:
 475 *   TEST_MIN_LENGTH - minimum size of packet to transfer
 476 *   TEST_MAX_LENGTH - maximum size of packet to transfer
 477 *   TEST_NUM - number of tests
 478 */
 479
 480#if CONFIG_POST & CONFIG_SYS_POST_SPI
 481
 482#define TEST_MIN_LENGTH         1
 483#define TEST_MAX_LENGTH         MAX_BUFFER
 484#define TEST_NUM                1
 485
 486static void packet_fill (char * packet, int length)
 487{
 488        char c = (char) length;
 489        int i;
 490
 491        for (i = 0; i < length; i++)
 492        {
 493            packet[i] = c++;
 494        }
 495}
 496
 497static int packet_check (char * packet, int length)
 498{
 499        char c = (char) length;
 500        int i;
 501
 502        for (i = 0; i < length; i++) {
 503            if (packet[i] != c++) return -1;
 504        }
 505
 506        return 0;
 507}
 508
 509int spi_post_test (int flags)
 510{
 511        int res = -1;
 512        volatile immap_t *immr = (immap_t *) CONFIG_SYS_IMMR;
 513        volatile cpm8xx_t *cp = (cpm8xx_t *) & immr->im_cpm;
 514        int i;
 515        int l;
 516
 517        spi_init_f ();
 518        spi_init_r ();
 519
 520        cp->cp_spmode |= SPMODE_LOOP;
 521
 522        for (i = 0; i < TEST_NUM; i++) {
 523                for (l = TEST_MIN_LENGTH; l <= TEST_MAX_LENGTH; l += 8) {
 524                        packet_fill ((char *)txbuf, l);
 525
 526                        spi_xfer (l);
 527
 528                        if (packet_check ((char *)rxbuf, l) < 0) {
 529                                goto Done;
 530                        }
 531                }
 532        }
 533
 534        res = 0;
 535
 536      Done:
 537
 538        cp->cp_spmode &= ~SPMODE_LOOP;
 539
 540        /*
 541         * SCC2 parameter RAM space overlaps
 542         * the SPI parameter RAM space. So we need to restore
 543         * the SCC2 configuration if it is used by UART.
 544         */
 545
 546#if !defined(CONFIG_8xx_CONS_NONE)
 547        serial_reinit_all ();
 548#endif
 549
 550        if (res != 0) {
 551                post_log ("SPI test failed\n");
 552        }
 553
 554        return res;
 555}
 556#endif  /* CONFIG_POST & CONFIG_SYS_POST_SPI */
 557