uboot/drivers/qe/qe.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2006-2009 Freescale Semiconductor, Inc.
   3 *
   4 * Dave Liu <daveliu@freescale.com>
   5 * based on source code of Shlomi Gridish
   6 *
   7 * This program is free software; you can redistribute it and/or
   8 * modify it under the terms of the GNU General Public License as
   9 * published by the Free Software Foundation; either version 2 of
  10 * the License, or (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
  20 * MA 02111-1307 USA
  21 */
  22
  23#include "common.h"
  24#include <command.h>
  25#include "asm/errno.h"
  26#include "asm/io.h"
  27#include "asm/immap_qe.h"
  28#include "qe.h"
  29
  30qe_map_t                *qe_immr = NULL;
  31static qe_snum_t        snums[QE_NUM_OF_SNUM];
  32
  33DECLARE_GLOBAL_DATA_PTR;
  34
  35void qe_issue_cmd(uint cmd, uint sbc, u8 mcn, u32 cmd_data)
  36{
  37        u32 cecr;
  38
  39        if (cmd == QE_RESET) {
  40                out_be32(&qe_immr->cp.cecr,(u32) (cmd | QE_CR_FLG));
  41        } else {
  42                out_be32(&qe_immr->cp.cecdr, cmd_data);
  43                out_be32(&qe_immr->cp.cecr, (sbc | QE_CR_FLG |
  44                         ((u32) mcn<<QE_CR_PROTOCOL_SHIFT) | cmd));
  45        }
  46        /* Wait for the QE_CR_FLG to clear */
  47        do {
  48                cecr = in_be32(&qe_immr->cp.cecr);
  49        } while (cecr & QE_CR_FLG);
  50
  51        return;
  52}
  53
  54uint qe_muram_alloc(uint size, uint align)
  55{
  56        uint    retloc;
  57        uint    align_mask, off;
  58        uint    savebase;
  59
  60        align_mask = align - 1;
  61        savebase = gd->mp_alloc_base;
  62
  63        if ((off = (gd->mp_alloc_base & align_mask)) != 0)
  64                gd->mp_alloc_base += (align - off);
  65
  66        if ((off = size & align_mask) != 0)
  67                size += (align - off);
  68
  69        if ((gd->mp_alloc_base + size) >= gd->mp_alloc_top) {
  70                gd->mp_alloc_base = savebase;
  71                printf("%s: ran out of ram.\n",  __FUNCTION__);
  72        }
  73
  74        retloc = gd->mp_alloc_base;
  75        gd->mp_alloc_base += size;
  76
  77        memset((void *)&qe_immr->muram[retloc], 0, size);
  78
  79        __asm__ __volatile__("sync");
  80
  81        return retloc;
  82}
  83
  84void *qe_muram_addr(uint offset)
  85{
  86        return (void *)&qe_immr->muram[offset];
  87}
  88
  89static void qe_sdma_init(void)
  90{
  91        volatile sdma_t *p;
  92        uint            sdma_buffer_base;
  93
  94        p = (volatile sdma_t *)&qe_immr->sdma;
  95
  96        /* All of DMA transaction in bus 1 */
  97        out_be32(&p->sdaqr, 0);
  98        out_be32(&p->sdaqmr, 0);
  99
 100        /* Allocate 2KB temporary buffer for sdma */
 101        sdma_buffer_base = qe_muram_alloc(2048, 4096);
 102        out_be32(&p->sdwbcr, sdma_buffer_base & QE_SDEBCR_BA_MASK);
 103
 104        /* Clear sdma status */
 105        out_be32(&p->sdsr, 0x03000000);
 106
 107        /* Enable global mode on bus 1, and 2KB buffer size */
 108        out_be32(&p->sdmr, QE_SDMR_GLB_1_MSK | (0x3 << QE_SDMR_CEN_SHIFT));
 109}
 110
 111/* This table is a list of the serial numbers of the Threads, taken from the
 112 * "SNUM Table" chart in the QE Reference Manual. The order is not important,
 113 * we just need to know what the SNUMs are for the threads.
 114 */
 115static u8 thread_snum[] = {
 116/* Evthreads 16-29 are not supported in MPC8309 */
 117#if !defined(CONFIG_MPC8309)
 118        0x04, 0x05, 0x0c, 0x0d,
 119        0x14, 0x15, 0x1c, 0x1d,
 120        0x24, 0x25, 0x2c, 0x2d,
 121        0x34, 0x35,
 122#endif
 123        0x88, 0x89, 0x98, 0x99,
 124        0xa8, 0xa9, 0xb8, 0xb9,
 125        0xc8, 0xc9, 0xd8, 0xd9,
 126        0xe8, 0xe9, 0x08, 0x09,
 127        0x18, 0x19, 0x28, 0x29,
 128        0x38, 0x39, 0x48, 0x49,
 129        0x58, 0x59, 0x68, 0x69,
 130        0x78, 0x79, 0x80, 0x81
 131};
 132
 133static void qe_snums_init(void)
 134{
 135        int     i;
 136
 137        for (i = 0; i < QE_NUM_OF_SNUM; i++) {
 138                snums[i].state = QE_SNUM_STATE_FREE;
 139                snums[i].num   = thread_snum[i];
 140        }
 141}
 142
 143int qe_get_snum(void)
 144{
 145        int     snum = -EBUSY;
 146        int     i;
 147
 148        for (i = 0; i < QE_NUM_OF_SNUM; i++) {
 149                if (snums[i].state == QE_SNUM_STATE_FREE) {
 150                        snums[i].state = QE_SNUM_STATE_USED;
 151                        snum = snums[i].num;
 152                        break;
 153                }
 154        }
 155
 156        return snum;
 157}
 158
 159void qe_put_snum(u8 snum)
 160{
 161        int     i;
 162
 163        for (i = 0; i < QE_NUM_OF_SNUM; i++) {
 164                if (snums[i].num == snum) {
 165                        snums[i].state = QE_SNUM_STATE_FREE;
 166                        break;
 167                }
 168        }
 169}
 170
 171void qe_init(uint qe_base)
 172{
 173        /* Init the QE IMMR base */
 174        qe_immr = (qe_map_t *)qe_base;
 175
 176#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NOR
 177        /*
 178         * Upload microcode to IRAM for those SOCs which do not have ROM in QE.
 179         */
 180        qe_upload_firmware((const void *)CONFIG_SYS_QE_FMAN_FW_ADDR);
 181
 182        /* enable the microcode in IRAM */
 183        out_be32(&qe_immr->iram.iready,QE_IRAM_READY);
 184#endif
 185
 186        gd->mp_alloc_base = QE_DATAONLY_BASE;
 187        gd->mp_alloc_top = gd->mp_alloc_base + QE_DATAONLY_SIZE;
 188
 189        qe_sdma_init();
 190        qe_snums_init();
 191}
 192
 193void qe_reset(void)
 194{
 195        qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
 196                         (u8) QE_CR_PROTOCOL_UNSPECIFIED, 0);
 197}
 198
 199void qe_assign_page(uint snum, uint para_ram_base)
 200{
 201        u32     cecr;
 202
 203        out_be32(&qe_immr->cp.cecdr, para_ram_base);
 204        out_be32(&qe_immr->cp.cecr, ((u32) snum<<QE_CR_ASSIGN_PAGE_SNUM_SHIFT)
 205                                         | QE_CR_FLG | QE_ASSIGN_PAGE);
 206
 207        /* Wait for the QE_CR_FLG to clear */
 208        do {
 209                cecr = in_be32(&qe_immr->cp.cecr);
 210        } while (cecr & QE_CR_FLG );
 211
 212        return;
 213}
 214
 215/*
 216 * brg: 0~15 as BRG1~BRG16
 217   rate: baud rate
 218 * BRG input clock comes from the BRGCLK (internal clock generated from
 219   the QE clock, it is one-half of the QE clock), If need the clock source
 220   from CLKn pin, we have te change the function.
 221 */
 222
 223#define BRG_CLK         (gd->brg_clk)
 224
 225int qe_set_brg(uint brg, uint rate)
 226{
 227        volatile uint   *bp;
 228        u32             divisor;
 229        int             div16 = 0;
 230
 231        if (brg >= QE_NUM_OF_BRGS)
 232                return -EINVAL;
 233        bp = (uint *)&qe_immr->brg.brgc1;
 234        bp += brg;
 235
 236        divisor = (BRG_CLK / rate);
 237        if (divisor > QE_BRGC_DIVISOR_MAX + 1) {
 238                div16 = 1;
 239                divisor /= 16;
 240        }
 241
 242        *bp = ((divisor - 1) << QE_BRGC_DIVISOR_SHIFT) | QE_BRGC_ENABLE;
 243        __asm__ __volatile__("sync");
 244
 245        if (div16) {
 246                *bp |= QE_BRGC_DIV16;
 247                __asm__ __volatile__("sync");
 248        }
 249
 250        return 0;
 251}
 252
 253/* Set ethernet MII clock master
 254*/
 255int qe_set_mii_clk_src(int ucc_num)
 256{
 257        u32     cmxgcr;
 258
 259        /* check if the UCC number is in range. */
 260        if ((ucc_num > UCC_MAX_NUM - 1) || (ucc_num < 0)) {
 261                printf("%s: ucc num not in ranges\n", __FUNCTION__);
 262                return -EINVAL;
 263        }
 264
 265        cmxgcr = in_be32(&qe_immr->qmx.cmxgcr);
 266        cmxgcr &= ~QE_CMXGCR_MII_ENET_MNG_MASK;
 267        cmxgcr |= (ucc_num <<QE_CMXGCR_MII_ENET_MNG_SHIFT);
 268        out_be32(&qe_immr->qmx.cmxgcr, cmxgcr);
 269
 270        return 0;
 271}
 272
 273/* Firmware information stored here for qe_get_firmware_info() */
 274static struct qe_firmware_info qe_firmware_info;
 275
 276/*
 277 * Set to 1 if QE firmware has been uploaded, and therefore
 278 * qe_firmware_info contains valid data.
 279 */
 280static int qe_firmware_uploaded;
 281
 282/*
 283 * Upload a QE microcode
 284 *
 285 * This function is a worker function for qe_upload_firmware().  It does
 286 * the actual uploading of the microcode.
 287 */
 288static void qe_upload_microcode(const void *base,
 289        const struct qe_microcode *ucode)
 290{
 291        const u32 *code = base + be32_to_cpu(ucode->code_offset);
 292        unsigned int i;
 293
 294        if (ucode->major || ucode->minor || ucode->revision)
 295                printf("QE: uploading microcode '%s' version %u.%u.%u\n",
 296                        ucode->id, ucode->major, ucode->minor, ucode->revision);
 297        else
 298                printf("QE: uploading microcode '%s'\n", ucode->id);
 299
 300        /* Use auto-increment */
 301        out_be32(&qe_immr->iram.iadd, be32_to_cpu(ucode->iram_offset) |
 302                QE_IRAM_IADD_AIE | QE_IRAM_IADD_BADDR);
 303
 304        for (i = 0; i < be32_to_cpu(ucode->count); i++)
 305                out_be32(&qe_immr->iram.idata, be32_to_cpu(code[i]));
 306}
 307
 308/*
 309 * Upload a microcode to the I-RAM at a specific address.
 310 *
 311 * See docs/README.qe_firmware for information on QE microcode uploading.
 312 *
 313 * Currently, only version 1 is supported, so the 'version' field must be
 314 * set to 1.
 315 *
 316 * The SOC model and revision are not validated, they are only displayed for
 317 * informational purposes.
 318 *
 319 * 'calc_size' is the calculated size, in bytes, of the firmware structure and
 320 * all of the microcode structures, minus the CRC.
 321 *
 322 * 'length' is the size that the structure says it is, including the CRC.
 323 */
 324int qe_upload_firmware(const struct qe_firmware *firmware)
 325{
 326        unsigned int i;
 327        unsigned int j;
 328        u32 crc;
 329        size_t calc_size = sizeof(struct qe_firmware);
 330        size_t length;
 331        const struct qe_header *hdr;
 332
 333        if (!firmware) {
 334                printf("Invalid address\n");
 335                return -EINVAL;
 336        }
 337
 338        hdr = &firmware->header;
 339        length = be32_to_cpu(hdr->length);
 340
 341        /* Check the magic */
 342        if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
 343            (hdr->magic[2] != 'F')) {
 344                printf("Not a microcode\n");
 345                return -EPERM;
 346        }
 347
 348        /* Check the version */
 349        if (hdr->version != 1) {
 350                printf("Unsupported version\n");
 351                return -EPERM;
 352        }
 353
 354        /* Validate some of the fields */
 355        if ((firmware->count < 1) || (firmware->count > MAX_QE_RISC)) {
 356                printf("Invalid data\n");
 357                return -EINVAL;
 358        }
 359
 360        /* Validate the length and check if there's a CRC */
 361        calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
 362
 363        for (i = 0; i < firmware->count; i++)
 364                /*
 365                 * For situations where the second RISC uses the same microcode
 366                 * as the first, the 'code_offset' and 'count' fields will be
 367                 * zero, so it's okay to add those.
 368                 */
 369                calc_size += sizeof(u32) *
 370                        be32_to_cpu(firmware->microcode[i].count);
 371
 372        /* Validate the length */
 373        if (length != calc_size + sizeof(u32)) {
 374                printf("Invalid length\n");
 375                return -EPERM;
 376        }
 377
 378        /*
 379         * Validate the CRC.  We would normally call crc32_no_comp(), but that
 380         * function isn't available unless you turn on JFFS support.
 381         */
 382        crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
 383        if (crc != (crc32(-1, (const void *) firmware, calc_size) ^ -1)) {
 384                printf("Firmware CRC is invalid\n");
 385                return -EIO;
 386        }
 387
 388        /*
 389         * If the microcode calls for it, split the I-RAM.
 390         */
 391        if (!firmware->split) {
 392                out_be16(&qe_immr->cp.cercr,
 393                        in_be16(&qe_immr->cp.cercr) | QE_CP_CERCR_CIR);
 394        }
 395
 396        if (firmware->soc.model)
 397                printf("Firmware '%s' for %u V%u.%u\n",
 398                        firmware->id, be16_to_cpu(firmware->soc.model),
 399                        firmware->soc.major, firmware->soc.minor);
 400        else
 401                printf("Firmware '%s'\n", firmware->id);
 402
 403        /*
 404         * The QE only supports one microcode per RISC, so clear out all the
 405         * saved microcode information and put in the new.
 406         */
 407        memset(&qe_firmware_info, 0, sizeof(qe_firmware_info));
 408        strcpy(qe_firmware_info.id, (char *)firmware->id);
 409        qe_firmware_info.extended_modes = firmware->extended_modes;
 410        memcpy(qe_firmware_info.vtraps, firmware->vtraps,
 411                sizeof(firmware->vtraps));
 412        qe_firmware_uploaded = 1;
 413
 414        /* Loop through each microcode. */
 415        for (i = 0; i < firmware->count; i++) {
 416                const struct qe_microcode *ucode = &firmware->microcode[i];
 417
 418                /* Upload a microcode if it's present */
 419                if (ucode->code_offset)
 420                        qe_upload_microcode(firmware, ucode);
 421
 422                /* Program the traps for this processor */
 423                for (j = 0; j < 16; j++) {
 424                        u32 trap = be32_to_cpu(ucode->traps[j]);
 425
 426                        if (trap)
 427                                out_be32(&qe_immr->rsp[i].tibcr[j], trap);
 428                }
 429
 430                /* Enable traps */
 431                out_be32(&qe_immr->rsp[i].eccr, be32_to_cpu(ucode->eccr));
 432        }
 433
 434        return 0;
 435}
 436
 437struct qe_firmware_info *qe_get_firmware_info(void)
 438{
 439        return qe_firmware_uploaded ? &qe_firmware_info : NULL;
 440}
 441
 442static int qe_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 443{
 444        ulong addr;
 445
 446        if (argc < 3)
 447                return cmd_usage(cmdtp);
 448
 449        if (strcmp(argv[1], "fw") == 0) {
 450                addr = simple_strtoul(argv[2], NULL, 16);
 451
 452                if (!addr) {
 453                        printf("Invalid address\n");
 454                        return -EINVAL;
 455                }
 456
 457                /*
 458                 * If a length was supplied, compare that with the 'length'
 459                 * field.
 460                 */
 461
 462                if (argc > 3) {
 463                        ulong length = simple_strtoul(argv[3], NULL, 16);
 464                        struct qe_firmware *firmware = (void *) addr;
 465
 466                        if (length != be32_to_cpu(firmware->header.length)) {
 467                                printf("Length mismatch\n");
 468                                return -EINVAL;
 469                        }
 470                }
 471
 472                return qe_upload_firmware((const struct qe_firmware *) addr);
 473        }
 474
 475        return cmd_usage(cmdtp);
 476}
 477
 478U_BOOT_CMD(
 479        qe, 4, 0, qe_cmd,
 480        "QUICC Engine commands",
 481        "fw <addr> [<length>] - Upload firmware binary at address <addr> to "
 482                "the QE,\n"
 483        "\twith optional length <length> verification."
 484);
 485