~ubuntu-branches/ubuntu/trusty/linux-armadaxp/trusty

« back to all changes in this revision

Viewing changes to drivers/mmc/host/mmci.c

  • Committer: Package Import Robot
  • Author(s): Michael Casadevall, Bryan Wu, Dann Frazier, Michael Casadeall
  • Date: 2012-03-10 15:00:54 UTC
  • mfrom: (1.1.1)
  • Revision ID: package-import@ubuntu.com-20120310150054-flugb39zon8vvgwe
Tags: 3.2.0-1600.1
[ Bryan Wu ]
* UBUNTU: import debian/debian.env and debian.armadaxp

[ Dann Frazier ]
* ARM: Armada XP: remove trailing '/' in dirnames in mvRules.mk

[ Michael Casadeall ]
* tools: add some tools for Marvell Armada XP processor
* kernel: timer tick hacking from Marvell
* kernel: Sheeva Errata: add delay on Sheeva when powering down
* net: add Marvell NFP netfilter
* net: socket and skb modifications made by Marvell
* miscdevice: add minor IDs for some Marvell Armada drivers
* fs: introduce memory pool for splice()
* video: EDID detection updates from Marvell Armada XP patchset
* video: backlight: add Marvell Dove LCD backlight driver
* video: display: add THS8200 display driver
* video: framebuffer: add Marvell Dove and Armada XP processor onchip LCD controller driver
* usbtest: add Interrupt transfer testing by Marvell Armada XP code
* usb: ehci: add support for Marvell EHCI controler
* tty/serial: 8250: add support for Marvell Armada XP processor and DeviceTree work
* rtc: add support for Marvell Armada XP onchip RTC controller
* net: pppoe: add Marvell ethernet NFP hook in PPPoE networking driver
* mtd: nand: add support for Marvell Armada XP Nand Flash Controller
* mtd: maps: add Marvell Armada XP specific map driver
* mmc: add support for Marvell Armada XP MMC/SD host controller
* i2c: add support for Marvell Armada XP onchip i2c bus controller
* hwmon: add Kconfig option for Armada XP onchip thermal sensor driver
* dmaengine: add Net DMA support for splice and update Marvell XOR DMA engine driver
* ata: add support for Marvell Armada XP SATA controller and update some quirks
* ARM: add Marvell Armada XP machine to mach-types
* ARM: oprofile: add support for Marvell PJ4B core
* ARM: mm: more ARMv6 switches for Marvell Armada XP
* ARM: remove static declaration to allow compilation
* ARM: alignment access fault trick
* ARM: mm: skip some fault fixing when run on NONE SMP ARMv6 mode during early abort event
* ARM: mm: add Marvell Sheeva CPU Architecture for PJ4B
* ARM: introduce optimized copy operation for Marvell Armada XP
* ARM: SAUCE: hardware breakpoint trick for Marvell Armada XP
* ARM: big endian and little endian tricks for Marvell Armada XP
* ARM: SAUCE: Add Marvell Armada XP build rules to arch/arm/kernel/Makefile
* ARM: vfp: add special handling for Marvell Armada XP
* ARM: add support for Marvell U-Boot
* ARM: add mv_controller_num for ARM PCI drivers
* ARM: add support for local PMUs, general SMP tweaks and cache flushing
* ARM: add Marvell device identifies in glue-proc.h
* ARM: add IPC driver support for Marvell platforms
* ARM: add DMA mapping for Marvell platforms
* ARM: add Sheeva errata and PJ4B code for booting
* ARM: update Kconfig and Makefile to include Marvell Armada XP platforms
* ARM: Armada XP: import LSP from Marvell for Armada XP 3.2 kernel enablement

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <linux/dmaengine.h>
30
30
#include <linux/dma-mapping.h>
31
31
#include <linux/amba/mmci.h>
 
32
#include <linux/pm_runtime.h>
32
33
 
33
34
#include <asm/div64.h>
34
35
#include <asm/io.h>
170
171
         * back into the driver...
171
172
         */
172
173
        spin_unlock(&host->lock);
 
174
        pm_runtime_put(mmc_dev(host->mmc));
173
175
        mmc_request_done(host->mmc, mrq);
174
176
        spin_lock(&host->lock);
175
177
}
226
228
                return;
227
229
        }
228
230
 
 
231
        /* initialize pre request cookie */
 
232
        host->next_data.cookie = 1;
 
233
 
229
234
        /* Try to acquire a generic DMA engine slave channel */
230
235
        dma_cap_zero(mask);
231
236
        dma_cap_set(DMA_SLAVE, mask);
335
340
                dir = DMA_FROM_DEVICE;
336
341
        }
337
342
 
338
 
        dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
 
343
        if (!data->host_cookie)
 
344
                dma_unmap_sg(chan->device->dev, data->sg, data->sg_len, dir);
339
345
 
340
346
        /*
341
347
         * Use of DMA with scatter-gather is impossible.
353
359
        dmaengine_terminate_all(host->dma_current);
354
360
}
355
361
 
356
 
static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 
362
static int mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
 
363
                              struct mmci_host_next *next)
357
364
{
358
365
        struct variant_data *variant = host->variant;
359
366
        struct dma_slave_config conf = {
364
371
                .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
365
372
                .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
366
373
        };
367
 
        struct mmc_data *data = host->data;
368
374
        struct dma_chan *chan;
369
375
        struct dma_device *device;
370
376
        struct dma_async_tx_descriptor *desc;
371
377
        int nr_sg;
372
378
 
373
 
        host->dma_current = NULL;
 
379
        /* Check if next job is already prepared */
 
380
        if (data->host_cookie && !next &&
 
381
            host->dma_current && host->dma_desc_current)
 
382
                return 0;
 
383
 
 
384
        if (!next) {
 
385
                host->dma_current = NULL;
 
386
                host->dma_desc_current = NULL;
 
387
        }
374
388
 
375
389
        if (data->flags & MMC_DATA_READ) {
376
390
                conf.direction = DMA_FROM_DEVICE;
385
399
                return -EINVAL;
386
400
 
387
401
        /* If less than or equal to the fifo size, don't bother with DMA */
388
 
        if (host->size <= variant->fifosize)
 
402
        if (data->blksz * data->blocks <= variant->fifosize)
389
403
                return -EINVAL;
390
404
 
391
405
        device = chan->device;
399
413
        if (!desc)
400
414
                goto unmap_exit;
401
415
 
 
416
        if (next) {
 
417
                next->dma_chan = chan;
 
418
                next->dma_desc = desc;
 
419
        } else {
 
420
                host->dma_current = chan;
 
421
                host->dma_desc_current = desc;
 
422
        }
 
423
 
 
424
        return 0;
 
425
 
 
426
 unmap_exit:
 
427
        if (!next)
 
428
                dmaengine_terminate_all(chan);
 
429
        dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction);
 
430
        return -ENOMEM;
 
431
}
 
432
 
 
433
static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
 
434
{
 
435
        int ret;
 
436
        struct mmc_data *data = host->data;
 
437
 
 
438
        ret = mmci_dma_prep_data(host, host->data, NULL);
 
439
        if (ret)
 
440
                return ret;
 
441
 
402
442
        /* Okay, go for it. */
403
 
        host->dma_current = chan;
404
 
 
405
443
        dev_vdbg(mmc_dev(host->mmc),
406
444
                 "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
407
445
                 data->sg_len, data->blksz, data->blocks, data->flags);
408
 
        dmaengine_submit(desc);
409
 
        dma_async_issue_pending(chan);
 
446
        dmaengine_submit(host->dma_desc_current);
 
447
        dma_async_issue_pending(host->dma_current);
410
448
 
411
449
        datactrl |= MCI_DPSM_DMAENABLE;
412
450
 
421
459
        writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
422
460
               host->base + MMCIMASK0);
423
461
        return 0;
424
 
 
425
 
unmap_exit:
426
 
        dmaengine_terminate_all(chan);
427
 
        dma_unmap_sg(device->dev, data->sg, data->sg_len, conf.direction);
428
 
        return -ENOMEM;
429
 
}
 
462
}
 
463
 
 
464
static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
 
465
{
 
466
        struct mmci_host_next *next = &host->next_data;
 
467
 
 
468
        if (data->host_cookie && data->host_cookie != next->cookie) {
 
469
                pr_warning("[%s] invalid cookie: data->host_cookie %d"
 
470
                       " host->next_data.cookie %d\n",
 
471
                       __func__, data->host_cookie, host->next_data.cookie);
 
472
                data->host_cookie = 0;
 
473
        }
 
474
 
 
475
        if (!data->host_cookie)
 
476
                return;
 
477
 
 
478
        host->dma_desc_current = next->dma_desc;
 
479
        host->dma_current = next->dma_chan;
 
480
 
 
481
        next->dma_desc = NULL;
 
482
        next->dma_chan = NULL;
 
483
}
 
484
 
 
485
static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq,
 
486
                             bool is_first_req)
 
487
{
 
488
        struct mmci_host *host = mmc_priv(mmc);
 
489
        struct mmc_data *data = mrq->data;
 
490
        struct mmci_host_next *nd = &host->next_data;
 
491
 
 
492
        if (!data)
 
493
                return;
 
494
 
 
495
        if (data->host_cookie) {
 
496
                data->host_cookie = 0;
 
497
                return;
 
498
        }
 
499
 
 
500
        /* if config for dma */
 
501
        if (((data->flags & MMC_DATA_WRITE) && host->dma_tx_channel) ||
 
502
            ((data->flags & MMC_DATA_READ) && host->dma_rx_channel)) {
 
503
                if (mmci_dma_prep_data(host, data, nd))
 
504
                        data->host_cookie = 0;
 
505
                else
 
506
                        data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
 
507
        }
 
508
}
 
509
 
 
510
static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
 
511
                              int err)
 
512
{
 
513
        struct mmci_host *host = mmc_priv(mmc);
 
514
        struct mmc_data *data = mrq->data;
 
515
        struct dma_chan *chan;
 
516
        enum dma_data_direction dir;
 
517
 
 
518
        if (!data)
 
519
                return;
 
520
 
 
521
        if (data->flags & MMC_DATA_READ) {
 
522
                dir = DMA_FROM_DEVICE;
 
523
                chan = host->dma_rx_channel;
 
524
        } else {
 
525
                dir = DMA_TO_DEVICE;
 
526
                chan = host->dma_tx_channel;
 
527
        }
 
528
 
 
529
 
 
530
        /* if config for dma */
 
531
        if (chan) {
 
532
                if (err)
 
533
                        dmaengine_terminate_all(chan);
 
534
                if (data->host_cookie)
 
535
                        dma_unmap_sg(mmc_dev(host->mmc), data->sg,
 
536
                                     data->sg_len, dir);
 
537
                mrq->data->host_cookie = 0;
 
538
        }
 
539
}
 
540
 
430
541
#else
431
542
/* Blank functions if the DMA engine is not available */
 
543
static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
 
544
{
 
545
}
432
546
static inline void mmci_dma_setup(struct mmci_host *host)
433
547
{
434
548
}
449
563
{
450
564
        return -ENOSYS;
451
565
}
 
566
 
 
567
#define mmci_pre_request NULL
 
568
#define mmci_post_request NULL
 
569
 
452
570
#endif
453
571
 
454
572
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
874
992
                return;
875
993
        }
876
994
 
 
995
        pm_runtime_get_sync(mmc_dev(mmc));
 
996
 
877
997
        spin_lock_irqsave(&host->lock, flags);
878
998
 
879
999
        host->mrq = mrq;
880
1000
 
 
1001
        if (mrq->data)
 
1002
                mmci_get_next_data(host, mrq->data);
 
1003
 
881
1004
        if (mrq->data && mrq->data->flags & MMC_DATA_READ)
882
1005
                mmci_start_data(host, mrq->data);
883
1006
 
992
1115
 
993
1116
static const struct mmc_host_ops mmci_ops = {
994
1117
        .request        = mmci_request,
 
1118
        .pre_req        = mmci_pre_request,
 
1119
        .post_req       = mmci_post_request,
995
1120
        .set_ios        = mmci_set_ios,
996
1121
        .get_ro         = mmci_get_ro,
997
1122
        .get_cd         = mmci_get_cd,
1041
1166
                goto host_free;
1042
1167
        }
1043
1168
 
 
1169
        ret = clk_prepare(host->clk);
 
1170
        if (ret)
 
1171
                goto clk_free;
 
1172
 
1044
1173
        ret = clk_enable(host->clk);
1045
1174
        if (ret)
1046
 
                goto clk_free;
 
1175
                goto clk_unprep;
1047
1176
 
1048
1177
        host->plat = plat;
1049
1178
        host->variant = variant;
1069
1198
        }
1070
1199
 
1071
1200
        mmc->ops = &mmci_ops;
1072
 
        mmc->f_min = (host->mclk + 511) / 512;
 
1201
        /*
 
1202
         * The ARM and ST versions of the block have slightly different
 
1203
         * clock divider equations which means that the minimum divider
 
1204
         * differs too.
 
1205
         */
 
1206
        if (variant->st_clkdiv)
 
1207
                mmc->f_min = DIV_ROUND_UP(host->mclk, 257);
 
1208
        else
 
1209
                mmc->f_min = DIV_ROUND_UP(host->mclk, 512);
1073
1210
        /*
1074
1211
         * If the platform data supplies a maximum operating
1075
1212
         * frequency, this takes precedence. Else, we fall back
1204
1341
 
1205
1342
        mmci_dma_setup(host);
1206
1343
 
 
1344
        pm_runtime_put(&dev->dev);
 
1345
 
1207
1346
        mmc_add_host(mmc);
1208
1347
 
1209
1348
        return 0;
1222
1361
        iounmap(host->base);
1223
1362
 clk_disable:
1224
1363
        clk_disable(host->clk);
 
1364
 clk_unprep:
 
1365
        clk_unprepare(host->clk);
1225
1366
 clk_free:
1226
1367
        clk_put(host->clk);
1227
1368
 host_free:
1241
1382
        if (mmc) {
1242
1383
                struct mmci_host *host = mmc_priv(mmc);
1243
1384
 
 
1385
                /*
 
1386
                 * Undo pm_runtime_put() in probe.  We use the _sync
 
1387
                 * version here so that we can access the primecell.
 
1388
                 */
 
1389
                pm_runtime_get_sync(&dev->dev);
 
1390
 
1244
1391
                mmc_remove_host(mmc);
1245
1392
 
1246
1393
                writel(0, host->base + MMCIMASK0);
1263
1410
 
1264
1411
                iounmap(host->base);
1265
1412
                clk_disable(host->clk);
 
1413
                clk_unprepare(host->clk);
1266
1414
                clk_put(host->clk);
1267
1415
 
1268
1416
                if (host->vcc)