~ubuntu-branches/ubuntu/vivid/u-boot/vivid

« back to all changes in this revision

Viewing changes to drivers/net/fm/fm.c

  • Committer: Package Import Robot
  • Author(s): Clint Adams
  • Date: 2012-01-02 17:49:39 UTC
  • mfrom: (1.2.7)
  • Revision ID: package-import@ubuntu.com-20120102174939-iddq37p3372x10yp
Tags: 2011.12-1
* New upstream version.
  - Drop build-timestamp_autogenerated.h-without-config.patch (merged).
  - Drop ublimage-NAND-block-size-isn-t-set-at-build-time.patch (merged).
  - Update kerma-sheevaplug-mvsdio.diff
  - Update mipsel-native-endianness.diff
  - Drop dreamplug-v8.patch (merged).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright 2009-2011 Freescale Semiconductor, Inc.
 
3
 *      Dave Liu <daveliu@freescale.com>
 
4
 *
 
5
 * This program is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU General Public License as
 
7
 * published by the Free Software Foundation; either version 2 of
 
8
 * the License, or (at your option) any later version.
 
9
 *
 
10
 * This program is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 * GNU General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU General Public License
 
16
 * along with this program; if not, write to the Free Software
 
17
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 
18
 * MA 02111-1307 USA
 
19
 */
 
20
#include <common.h>
 
21
#include <malloc.h>
 
22
#include <asm/io.h>
 
23
#include <asm/errno.h>
 
24
 
 
25
#include "fm.h"
 
26
#include "../../qe/qe.h"                /* For struct qe_firmware */
 
27
 
 
28
#ifdef CONFIG_SYS_QE_FMAN_FW_IN_NAND
 
29
#include <nand.h>
 
30
#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
 
31
#include <spi_flash.h>
 
32
#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC)
 
33
#include <mmc.h>
 
34
#endif
 
35
 
 
36
struct fm_muram muram[CONFIG_SYS_NUM_FMAN];
 
37
 
 
38
u32 fm_muram_base(int fm_idx)
 
39
{
 
40
        return muram[fm_idx].base;
 
41
}
 
42
 
 
43
u32 fm_muram_alloc(int fm_idx, u32 size, u32 align)
 
44
{
 
45
        u32 ret;
 
46
        u32 align_mask, off;
 
47
        u32 save;
 
48
 
 
49
        align_mask = align - 1;
 
50
        save = muram[fm_idx].alloc;
 
51
 
 
52
        off = save & align_mask;
 
53
        if (off != 0)
 
54
                muram[fm_idx].alloc += (align - off);
 
55
        off = size & align_mask;
 
56
        if (off != 0)
 
57
                size += (align - off);
 
58
        if ((muram[fm_idx].alloc + size) >= muram[fm_idx].top) {
 
59
                muram[fm_idx].alloc = save;
 
60
                printf("%s: run out of ram.\n", __func__);
 
61
        }
 
62
 
 
63
        ret = muram[fm_idx].alloc;
 
64
        muram[fm_idx].alloc += size;
 
65
        memset((void *)ret, 0, size);
 
66
 
 
67
        return ret;
 
68
}
 
69
 
 
70
static void fm_init_muram(int fm_idx, void *reg)
 
71
{
 
72
        u32 base = (u32)reg;
 
73
 
 
74
        muram[fm_idx].base = base;
 
75
        muram[fm_idx].size = CONFIG_SYS_FM_MURAM_SIZE;
 
76
        muram[fm_idx].alloc = base + FM_MURAM_RES_SIZE;
 
77
        muram[fm_idx].top = base + CONFIG_SYS_FM_MURAM_SIZE;
 
78
}
 
79
 
 
80
/*
 
81
 * fm_upload_ucode - Fman microcode upload worker function
 
82
 *
 
83
 * This function does the actual uploading of an Fman microcode
 
84
 * to an Fman.
 
85
 */
 
86
static void fm_upload_ucode(int fm_idx, struct fm_imem *imem,
 
87
                            u32 *ucode, unsigned int size)
 
88
{
 
89
        unsigned int i;
 
90
        unsigned int timeout = 1000000;
 
91
 
 
92
        /* enable address auto increase */
 
93
        out_be32(&imem->iadd, IRAM_IADD_AIE);
 
94
        /* write microcode to IRAM */
 
95
        for (i = 0; i < size / 4; i++)
 
96
                out_be32(&imem->idata, ucode[i]);
 
97
 
 
98
        /* verify if the writing is over */
 
99
        out_be32(&imem->iadd, 0);
 
100
        while ((in_be32(&imem->idata) != ucode[0]) && --timeout)
 
101
                ;
 
102
        if (!timeout)
 
103
                printf("Fman%u: microcode upload timeout\n", fm_idx + 1);
 
104
 
 
105
        /* enable microcode from IRAM */
 
106
        out_be32(&imem->iready, IRAM_READY);
 
107
}
 
108
 
 
109
/*
 
110
 * Upload an Fman firmware
 
111
 *
 
112
 * This function is similar to qe_upload_firmware(), exception that it uploads
 
113
 * a microcode to the Fman instead of the QE.
 
114
 *
 
115
 * Because the process for uploading a microcode to the Fman is similar for
 
116
 * that of the QE, the QE firmware binary format is used for Fman microcode.
 
117
 * It should be possible to unify these two functions, but for now we keep them
 
118
 * separate.
 
119
 */
 
120
static int fman_upload_firmware(int fm_idx,
 
121
                                struct fm_imem *fm_imem,
 
122
                                const struct qe_firmware *firmware)
 
123
{
 
124
        unsigned int i;
 
125
        u32 crc;
 
126
        size_t calc_size = sizeof(struct qe_firmware);
 
127
        size_t length;
 
128
        const struct qe_header *hdr;
 
129
 
 
130
        if (!firmware) {
 
131
                printf("Fman%u: Invalid address for firmware\n", fm_idx + 1);
 
132
                return -EINVAL;
 
133
        }
 
134
 
 
135
        hdr = &firmware->header;
 
136
        length = be32_to_cpu(hdr->length);
 
137
 
 
138
        /* Check the magic */
 
139
        if ((hdr->magic[0] != 'Q') || (hdr->magic[1] != 'E') ||
 
140
                (hdr->magic[2] != 'F')) {
 
141
                printf("Fman%u: Data at %p is not a firmware\n", fm_idx + 1,
 
142
                       firmware);
 
143
                return -EPERM;
 
144
        }
 
145
 
 
146
        /* Check the version */
 
147
        if (hdr->version != 1) {
 
148
                printf("Fman%u: Unsupported firmware version %u\n", fm_idx + 1,
 
149
                       hdr->version);
 
150
                return -EPERM;
 
151
        }
 
152
 
 
153
        /* Validate some of the fields */
 
154
        if ((firmware->count != 1)) {
 
155
                printf("Fman%u: Invalid data in firmware header\n", fm_idx + 1);
 
156
                return -EINVAL;
 
157
        }
 
158
 
 
159
        /* Validate the length and check if there's a CRC */
 
160
        calc_size += (firmware->count - 1) * sizeof(struct qe_microcode);
 
161
 
 
162
        for (i = 0; i < firmware->count; i++)
 
163
                /*
 
164
                 * For situations where the second RISC uses the same microcode
 
165
                 * as the first, the 'code_offset' and 'count' fields will be
 
166
                 * zero, so it's okay to add those.
 
167
                 */
 
168
                calc_size += sizeof(u32) *
 
169
                        be32_to_cpu(firmware->microcode[i].count);
 
170
 
 
171
        /* Validate the length */
 
172
        if (length != calc_size + sizeof(u32)) {
 
173
                printf("Fman%u: Invalid length in firmware header\n",
 
174
                       fm_idx + 1);
 
175
                return -EPERM;
 
176
        }
 
177
 
 
178
        /*
 
179
         * Validate the CRC.  We would normally call crc32_no_comp(), but that
 
180
         * function isn't available unless you turn on JFFS support.
 
181
         */
 
182
        crc = be32_to_cpu(*(u32 *)((void *)firmware + calc_size));
 
183
        if (crc != (crc32(-1, (const void *)firmware, calc_size) ^ -1)) {
 
184
                printf("Fman%u: Firmware CRC is invalid\n", fm_idx + 1);
 
185
                return -EIO;
 
186
        }
 
187
 
 
188
        /* Loop through each microcode. */
 
189
        for (i = 0; i < firmware->count; i++) {
 
190
                const struct qe_microcode *ucode = &firmware->microcode[i];
 
191
 
 
192
                /* Upload a microcode if it's present */
 
193
                if (ucode->code_offset) {
 
194
                        u32 ucode_size;
 
195
                        u32 *code;
 
196
                        printf("Fman%u: Uploading microcode version %u.%u.%u\n",
 
197
                               fm_idx + 1, ucode->major, ucode->minor,
 
198
                               ucode->revision);
 
199
                        code = (void *)firmware + ucode->code_offset;
 
200
                        ucode_size = sizeof(u32) * ucode->count;
 
201
                        fm_upload_ucode(fm_idx, fm_imem, code, ucode_size);
 
202
                }
 
203
        }
 
204
 
 
205
        return 0;
 
206
}
 
207
 
 
208
static u32 fm_assign_risc(int port_id)
 
209
{
 
210
        u32 risc_sel, val;
 
211
        risc_sel = (port_id & 0x1) ? FMFPPRC_RISC2 : FMFPPRC_RISC1;
 
212
        val = (port_id << FMFPPRC_PORTID_SHIFT) & FMFPPRC_PORTID_MASK;
 
213
        val |= ((risc_sel << FMFPPRC_ORA_SHIFT) | risc_sel);
 
214
 
 
215
        return val;
 
216
}
 
217
 
 
218
static void fm_init_fpm(struct fm_fpm *fpm)
 
219
{
 
220
        int i, port_id;
 
221
        u32 val;
 
222
 
 
223
        setbits_be32(&fpm->fmfpee, FMFPEE_EHM | FMFPEE_UEC |
 
224
                                   FMFPEE_CER | FMFPEE_DER);
 
225
 
 
226
        /* IM mode, each even port ID to RISC#1, each odd port ID to RISC#2 */
 
227
 
 
228
        /* offline/parser port */
 
229
        for (i = 0; i < MAX_NUM_OH_PORT; i++) {
 
230
                port_id = OH_PORT_ID_BASE + i;
 
231
                val = fm_assign_risc(port_id);
 
232
                out_be32(&fpm->fpmprc, val);
 
233
        }
 
234
        /* Rx 1G port */
 
235
        for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
 
236
                port_id = RX_PORT_1G_BASE + i;
 
237
                val = fm_assign_risc(port_id);
 
238
                out_be32(&fpm->fpmprc, val);
 
239
        }
 
240
        /* Tx 1G port */
 
241
        for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
 
242
                port_id = TX_PORT_1G_BASE + i;
 
243
                val = fm_assign_risc(port_id);
 
244
                out_be32(&fpm->fpmprc, val);
 
245
        }
 
246
        /* Rx 10G port */
 
247
        port_id = RX_PORT_10G_BASE;
 
248
        val = fm_assign_risc(port_id);
 
249
        out_be32(&fpm->fpmprc, val);
 
250
        /* Tx 10G port */
 
251
        port_id = TX_PORT_10G_BASE;
 
252
        val = fm_assign_risc(port_id);
 
253
        out_be32(&fpm->fpmprc, val);
 
254
 
 
255
        /* disable the dispatch limit in IM case */
 
256
        out_be32(&fpm->fpmflc, FMFP_FLC_DISP_LIM_NONE);
 
257
        /* clear events */
 
258
        out_be32(&fpm->fmfpee, FMFPEE_CLEAR_EVENT);
 
259
 
 
260
        /* clear risc events */
 
261
        for (i = 0; i < 4; i++)
 
262
                out_be32(&fpm->fpmcev[i], 0xffffffff);
 
263
 
 
264
        /* clear error */
 
265
        out_be32(&fpm->fpmrcr, FMFP_RCR_MDEC | FMFP_RCR_IDEC);
 
266
}
 
267
 
 
268
static int fm_init_bmi(int fm_idx, struct fm_bmi_common *bmi)
 
269
{
 
270
        int blk, i, port_id;
 
271
        u32 val, offset, base;
 
272
 
 
273
        /* alloc free buffer pool in MURAM */
 
274
        base = fm_muram_alloc(fm_idx, FM_FREE_POOL_SIZE, FM_FREE_POOL_ALIGN);
 
275
        if (!base) {
 
276
                printf("%s: no muram for free buffer pool\n", __func__);
 
277
                return -ENOMEM;
 
278
        }
 
279
        offset = base - fm_muram_base(fm_idx);
 
280
 
 
281
        /* Need 128KB total free buffer pool size */
 
282
        val = offset / 256;
 
283
        blk = FM_FREE_POOL_SIZE / 256;
 
284
        /* in IM, we must not begin from offset 0 in MURAM */
 
285
        val |= ((blk - 1) << FMBM_CFG1_FBPS_SHIFT);
 
286
        out_be32(&bmi->fmbm_cfg1, val);
 
287
 
 
288
        /* disable all BMI interrupt */
 
289
        out_be32(&bmi->fmbm_ier, FMBM_IER_DISABLE_ALL);
 
290
 
 
291
        /* clear all events */
 
292
        out_be32(&bmi->fmbm_ievr, FMBM_IEVR_CLEAR_ALL);
 
293
 
 
294
        /*
 
295
         * set port parameters - FMBM_PP_x
 
296
         * max tasks 10G Rx/Tx=12, 1G Rx/Tx 4, others is 1
 
297
         * max dma 10G Rx/Tx=3, others is 1
 
298
         * set port FIFO size - FMBM_PFS_x
 
299
         * 4KB for all Rx and Tx ports
 
300
         */
 
301
        /* offline/parser port */
 
302
        for (i = 0; i < MAX_NUM_OH_PORT; i++) {
 
303
                port_id = OH_PORT_ID_BASE + i - 1;
 
304
                /* max tasks=1, max dma=1, no extra */
 
305
                out_be32(&bmi->fmbm_pp[port_id], 0);
 
306
                /* port FIFO size - 256 bytes, no extra */
 
307
                out_be32(&bmi->fmbm_pfs[port_id], 0);
 
308
        }
 
309
        /* Rx 1G port */
 
310
        for (i = 0; i < MAX_NUM_RX_PORT_1G; i++) {
 
311
                port_id = RX_PORT_1G_BASE + i - 1;
 
312
                /* max tasks=4, max dma=1, no extra */
 
313
                out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
 
314
                /* FIFO size - 4KB, no extra */
 
315
                out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
 
316
        }
 
317
        /* Tx 1G port FIFO size - 4KB, no extra */
 
318
        for (i = 0; i < MAX_NUM_TX_PORT_1G; i++) {
 
319
                port_id = TX_PORT_1G_BASE + i - 1;
 
320
                /* max tasks=4, max dma=1, no extra */
 
321
                out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(4));
 
322
                /* FIFO size - 4KB, no extra */
 
323
                out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
 
324
        }
 
325
        /* Rx 10G port */
 
326
        port_id = RX_PORT_10G_BASE - 1;
 
327
        /* max tasks=12, max dma=3, no extra */
 
328
        out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
 
329
        /* FIFO size - 4KB, no extra */
 
330
        out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
 
331
 
 
332
        /* Tx 10G port */
 
333
        port_id = TX_PORT_10G_BASE - 1;
 
334
        /* max tasks=12, max dma=3, no extra */
 
335
        out_be32(&bmi->fmbm_pp[port_id], FMBM_PP_MXT(12) | FMBM_PP_MXD(3));
 
336
        /* FIFO size - 4KB, no extra */
 
337
        out_be32(&bmi->fmbm_pfs[port_id], FMBM_PFS_IFSZ(0xf));
 
338
 
 
339
        /* initialize internal buffers data base (linked list) */
 
340
        out_be32(&bmi->fmbm_init, FMBM_INIT_START);
 
341
 
 
342
        return 0;
 
343
}
 
344
 
 
345
static void fm_init_qmi(struct fm_qmi_common *qmi)
 
346
{
 
347
        /* disable enqueue and dequeue of QMI */
 
348
        clrbits_be32(&qmi->fmqm_gc, FMQM_GC_ENQ_EN | FMQM_GC_DEQ_EN);
 
349
 
 
350
        /* disable all error interrupts */
 
351
        out_be32(&qmi->fmqm_eien, FMQM_EIEN_DISABLE_ALL);
 
352
        /* clear all error events */
 
353
        out_be32(&qmi->fmqm_eie, FMQM_EIE_CLEAR_ALL);
 
354
 
 
355
        /* disable all interrupts */
 
356
        out_be32(&qmi->fmqm_ien, FMQM_IEN_DISABLE_ALL);
 
357
        /* clear all interrupts */
 
358
        out_be32(&qmi->fmqm_ie, FMQM_IE_CLEAR_ALL);
 
359
}
 
360
 
 
361
/* Init common part of FM, index is fm num# like fm as above */
 
362
int fm_init_common(int index, struct ccsr_fman *reg)
 
363
{
 
364
        int rc;
 
365
        char env_addr[32];
 
366
#if defined(CONFIG_SYS_QE_FMAN_FW_IN_NOR)
 
367
        void *addr = (void *)CONFIG_SYS_QE_FMAN_FW_ADDR;
 
368
#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_NAND)
 
369
        size_t fw_length = CONFIG_SYS_QE_FMAN_FW_LENGTH;
 
370
        void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
 
371
 
 
372
        rc = nand_read(&nand_info[0], (loff_t)CONFIG_SYS_QE_FMAN_FW_ADDR,
 
373
                       &fw_length, (u_char *)addr);
 
374
        if (rc == -EUCLEAN) {
 
375
                printf("NAND read of FMAN firmware at offset 0x%x failed %d\n",
 
376
                        CONFIG_SYS_QE_FMAN_FW_ADDR, rc);
 
377
        }
 
378
#elif defined(CONFIG_SYS_QE_FW_IN_SPIFLASH)
 
379
        struct spi_flash *ucode_flash;
 
380
        void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
 
381
        int ret = 0;
 
382
 
 
383
        ucode_flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
 
384
                        CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
 
385
        if (!ucode_flash)
 
386
                printf("SF: probe for ucode failed\n");
 
387
        else {
 
388
                ret = spi_flash_read(ucode_flash, CONFIG_SYS_QE_FMAN_FW_ADDR,
 
389
                                CONFIG_SYS_QE_FMAN_FW_LENGTH, addr);
 
390
                if (ret)
 
391
                        printf("SF: read for ucode failed\n");
 
392
                spi_flash_free(ucode_flash);
 
393
        }
 
394
#elif defined(CONFIG_SYS_QE_FMAN_FW_IN_MMC)
 
395
        int dev = CONFIG_SYS_MMC_ENV_DEV;
 
396
        void *addr = malloc(CONFIG_SYS_QE_FMAN_FW_LENGTH);
 
397
        u32 cnt = CONFIG_SYS_QE_FMAN_FW_LENGTH / 512;
 
398
        u32 blk = CONFIG_SYS_QE_FMAN_FW_ADDR / 512;
 
399
        struct mmc *mmc = find_mmc_device(CONFIG_SYS_MMC_ENV_DEV);
 
400
 
 
401
        if (!mmc)
 
402
                printf("\nMMC cannot find device for ucode\n");
 
403
        else {
 
404
                printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
 
405
                                dev, blk, cnt);
 
406
                mmc_init(mmc);
 
407
                (void)mmc->block_dev.block_read(dev, blk, cnt, addr);
 
408
                /* flush cache after read */
 
409
                flush_cache((ulong)addr, cnt * 512);
 
410
        }
 
411
#endif
 
412
 
 
413
        /* Upload the Fman microcode if it's present */
 
414
        rc = fman_upload_firmware(index, &reg->fm_imem, addr);
 
415
        if (rc)
 
416
                return rc;
 
417
        sprintf(env_addr, "0x%lx", (long unsigned int)addr);
 
418
        setenv("fman_ucode", env_addr);
 
419
 
 
420
        fm_init_muram(index, &reg->muram);
 
421
        fm_init_qmi(&reg->fm_qmi_common);
 
422
        fm_init_fpm(&reg->fm_fpm);
 
423
 
 
424
        /* clear DMA status */
 
425
        setbits_be32(&reg->fm_dma.fmdmsr, FMDMSR_CLEAR_ALL);
 
426
 
 
427
        /* set DMA mode */
 
428
        setbits_be32(&reg->fm_dma.fmdmmr, FMDMMR_SBER);
 
429
 
 
430
        return fm_init_bmi(index, &reg->fm_bmi_common);
 
431
}