linux/arch/powerpc/sysdev/fsl_lbc.c
<<
>>
Prefs
   1/*
   2 * Freescale LBC and UPM routines.
   3 *
   4 * Copyright © 2007-2008  MontaVista Software, Inc.
   5 * Copyright © 2010 Freescale Semiconductor
   6 *
   7 * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
   8 * Author: Jack Lan <Jack.Lan@freescale.com>
   9 * Author: Roy Zang <tie-fei.zang@freescale.com>
  10 *
  11 * This program is free software; you can redistribute it and/or modify
  12 * it under the terms of the GNU General Public License as published by
  13 * the Free Software Foundation; either version 2 of the License, or
  14 * (at your option) any later version.
  15 */
  16
  17#include <linux/init.h>
  18#include <linux/export.h>
  19#include <linux/kernel.h>
  20#include <linux/compiler.h>
  21#include <linux/spinlock.h>
  22#include <linux/types.h>
  23#include <linux/io.h>
  24#include <linux/of.h>
  25#include <linux/slab.h>
  26#include <linux/sched.h>
  27#include <linux/platform_device.h>
  28#include <linux/interrupt.h>
  29#include <linux/mod_devicetable.h>
  30#include <linux/syscore_ops.h>
  31#include <asm/prom.h>
  32#include <asm/fsl_lbc.h>
  33
  34static spinlock_t fsl_lbc_lock = __SPIN_LOCK_UNLOCKED(fsl_lbc_lock);
  35struct fsl_lbc_ctrl *fsl_lbc_ctrl_dev;
  36EXPORT_SYMBOL(fsl_lbc_ctrl_dev);
  37
  38/**
  39 * fsl_lbc_addr - convert the base address
  40 * @addr_base:  base address of the memory bank
  41 *
  42 * This function converts a base address of lbc into the right format for the
  43 * BR register. If the SOC has eLBC then it returns 32bit physical address
  44 * else it convers a 34bit local bus physical address to correct format of
  45 * 32bit address for BR register (Example: MPC8641).
  46 */
  47u32 fsl_lbc_addr(phys_addr_t addr_base)
  48{
  49        struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node;
  50        u32 addr = addr_base & 0xffff8000;
  51
  52        if (of_device_is_compatible(np, "fsl,elbc"))
  53                return addr;
  54
  55        return addr | ((addr_base & 0x300000000ull) >> 19);
  56}
  57EXPORT_SYMBOL(fsl_lbc_addr);
  58
  59/**
  60 * fsl_lbc_find - find Localbus bank
  61 * @addr_base:  base address of the memory bank
  62 *
  63 * This function walks LBC banks comparing "Base address" field of the BR
  64 * registers with the supplied addr_base argument. When bases match this
  65 * function returns bank number (starting with 0), otherwise it returns
  66 * appropriate errno value.
  67 */
  68int fsl_lbc_find(phys_addr_t addr_base)
  69{
  70        int i;
  71        struct fsl_lbc_regs __iomem *lbc;
  72
  73        if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
  74                return -ENODEV;
  75
  76        lbc = fsl_lbc_ctrl_dev->regs;
  77        for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
  78                u32 br = in_be32(&lbc->bank[i].br);
  79                u32 or = in_be32(&lbc->bank[i].or);
  80
  81                if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base))
  82                        return i;
  83        }
  84
  85        return -ENOENT;
  86}
  87EXPORT_SYMBOL(fsl_lbc_find);
  88
  89/**
  90 * fsl_upm_find - find pre-programmed UPM via base address
  91 * @addr_base:  base address of the memory bank controlled by the UPM
  92 * @upm:        pointer to the allocated fsl_upm structure
  93 *
  94 * This function fills fsl_upm structure so you can use it with the rest of
  95 * UPM API. On success this function returns 0, otherwise it returns
  96 * appropriate errno value.
  97 */
  98int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
  99{
 100        int bank;
 101        u32 br;
 102        struct fsl_lbc_regs __iomem *lbc;
 103
 104        bank = fsl_lbc_find(addr_base);
 105        if (bank < 0)
 106                return bank;
 107
 108        if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
 109                return -ENODEV;
 110
 111        lbc = fsl_lbc_ctrl_dev->regs;
 112        br = in_be32(&lbc->bank[bank].br);
 113
 114        switch (br & BR_MSEL) {
 115        case BR_MS_UPMA:
 116                upm->mxmr = &lbc->mamr;
 117                break;
 118        case BR_MS_UPMB:
 119                upm->mxmr = &lbc->mbmr;
 120                break;
 121        case BR_MS_UPMC:
 122                upm->mxmr = &lbc->mcmr;
 123                break;
 124        default:
 125                return -EINVAL;
 126        }
 127
 128        switch (br & BR_PS) {
 129        case BR_PS_8:
 130                upm->width = 8;
 131                break;
 132        case BR_PS_16:
 133                upm->width = 16;
 134                break;
 135        case BR_PS_32:
 136                upm->width = 32;
 137                break;
 138        default:
 139                return -EINVAL;
 140        }
 141
 142        return 0;
 143}
 144EXPORT_SYMBOL(fsl_upm_find);
 145
 146/**
 147 * fsl_upm_run_pattern - actually run an UPM pattern
 148 * @upm:        pointer to the fsl_upm structure obtained via fsl_upm_find
 149 * @io_base:    remapped pointer to where memory access should happen
 150 * @mar:        MAR register content during pattern execution
 151 *
 152 * This function triggers dummy write to the memory specified by the io_base,
 153 * thus UPM pattern actually executed. Note that mar usage depends on the
 154 * pre-programmed AMX bits in the UPM RAM.
 155 */
 156int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
 157{
 158        int ret = 0;
 159        unsigned long flags;
 160
 161        if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
 162                return -ENODEV;
 163
 164        spin_lock_irqsave(&fsl_lbc_lock, flags);
 165
 166        out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
 167
 168        switch (upm->width) {
 169        case 8:
 170                out_8(io_base, 0x0);
 171                break;
 172        case 16:
 173                out_be16(io_base, 0x0);
 174                break;
 175        case 32:
 176                out_be32(io_base, 0x0);
 177                break;
 178        default:
 179                ret = -EINVAL;
 180                break;
 181        }
 182
 183        spin_unlock_irqrestore(&fsl_lbc_lock, flags);
 184
 185        return ret;
 186}
 187EXPORT_SYMBOL(fsl_upm_run_pattern);
 188
 189static int fsl_lbc_ctrl_init(struct fsl_lbc_ctrl *ctrl,
 190                             struct device_node *node)
 191{
 192        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
 193
 194        /* clear event registers */
 195        setbits32(&lbc->ltesr, LTESR_CLEAR);
 196        out_be32(&lbc->lteatr, 0);
 197        out_be32(&lbc->ltear, 0);
 198        out_be32(&lbc->lteccr, LTECCR_CLEAR);
 199        out_be32(&lbc->ltedr, LTEDR_ENABLE);
 200
 201        /* Set the monitor timeout value to the maximum for erratum A001 */
 202        if (of_device_is_compatible(node, "fsl,elbc"))
 203                clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS);
 204
 205        return 0;
 206}
 207
 208/*
 209 * NOTE: This interrupt is used to report localbus events of various kinds,
 210 * such as transaction errors on the chipselects.
 211 */
 212
 213static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
 214{
 215        struct fsl_lbc_ctrl *ctrl = data;
 216        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
 217        u32 status;
 218        unsigned long flags;
 219
 220        spin_lock_irqsave(&fsl_lbc_lock, flags);
 221        status = in_be32(&lbc->ltesr);
 222        if (!status) {
 223                spin_unlock_irqrestore(&fsl_lbc_lock, flags);
 224                return IRQ_NONE;
 225        }
 226
 227        out_be32(&lbc->ltesr, LTESR_CLEAR);
 228        out_be32(&lbc->lteatr, 0);
 229        out_be32(&lbc->ltear, 0);
 230        ctrl->irq_status = status;
 231
 232        if (status & LTESR_BM)
 233                dev_err(ctrl->dev, "Local bus monitor time-out: "
 234                        "LTESR 0x%08X\n", status);
 235        if (status & LTESR_WP)
 236                dev_err(ctrl->dev, "Write protect error: "
 237                        "LTESR 0x%08X\n", status);
 238        if (status & LTESR_ATMW)
 239                dev_err(ctrl->dev, "Atomic write error: "
 240                        "LTESR 0x%08X\n", status);
 241        if (status & LTESR_ATMR)
 242                dev_err(ctrl->dev, "Atomic read error: "
 243                        "LTESR 0x%08X\n", status);
 244        if (status & LTESR_CS)
 245                dev_err(ctrl->dev, "Chip select error: "
 246                        "LTESR 0x%08X\n", status);
 247        if (status & LTESR_FCT) {
 248                dev_err(ctrl->dev, "FCM command time-out: "
 249                        "LTESR 0x%08X\n", status);
 250                smp_wmb();
 251                wake_up(&ctrl->irq_wait);
 252        }
 253        if (status & LTESR_PAR) {
 254                dev_err(ctrl->dev, "Parity or Uncorrectable ECC error: "
 255                        "LTESR 0x%08X\n", status);
 256                smp_wmb();
 257                wake_up(&ctrl->irq_wait);
 258        }
 259        if (status & LTESR_CC) {
 260                smp_wmb();
 261                wake_up(&ctrl->irq_wait);
 262        }
 263        if (status & ~LTESR_MASK)
 264                dev_err(ctrl->dev, "Unknown error: "
 265                        "LTESR 0x%08X\n", status);
 266        spin_unlock_irqrestore(&fsl_lbc_lock, flags);
 267        return IRQ_HANDLED;
 268}
 269
 270/*
 271 * fsl_lbc_ctrl_probe
 272 *
 273 * called by device layer when it finds a device matching
 274 * one our driver can handled. This code allocates all of
 275 * the resources needed for the controller only.  The
 276 * resources for the NAND banks themselves are allocated
 277 * in the chip probe function.
 278*/
 279
 280static int fsl_lbc_ctrl_probe(struct platform_device *dev)
 281{
 282        int ret;
 283
 284        if (!dev->dev.of_node) {
 285                dev_err(&dev->dev, "Device OF-Node is NULL");
 286                return -EFAULT;
 287        }
 288
 289        fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL);
 290        if (!fsl_lbc_ctrl_dev)
 291                return -ENOMEM;
 292
 293        dev_set_drvdata(&dev->dev, fsl_lbc_ctrl_dev);
 294
 295        spin_lock_init(&fsl_lbc_ctrl_dev->lock);
 296        init_waitqueue_head(&fsl_lbc_ctrl_dev->irq_wait);
 297
 298        fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0);
 299        if (!fsl_lbc_ctrl_dev->regs) {
 300                dev_err(&dev->dev, "failed to get memory region\n");
 301                ret = -ENODEV;
 302                goto err;
 303        }
 304
 305        fsl_lbc_ctrl_dev->irq[0] = irq_of_parse_and_map(dev->dev.of_node, 0);
 306        if (!fsl_lbc_ctrl_dev->irq[0]) {
 307                dev_err(&dev->dev, "failed to get irq resource\n");
 308                ret = -ENODEV;
 309                goto err;
 310        }
 311
 312        fsl_lbc_ctrl_dev->dev = &dev->dev;
 313
 314        ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node);
 315        if (ret < 0)
 316                goto err;
 317
 318        ret = request_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_irq, 0,
 319                                "fsl-lbc", fsl_lbc_ctrl_dev);
 320        if (ret != 0) {
 321                dev_err(&dev->dev, "failed to install irq (%d)\n",
 322                        fsl_lbc_ctrl_dev->irq[0]);
 323                ret = fsl_lbc_ctrl_dev->irq[0];
 324                goto err;
 325        }
 326
 327        fsl_lbc_ctrl_dev->irq[1] = irq_of_parse_and_map(dev->dev.of_node, 1);
 328        if (fsl_lbc_ctrl_dev->irq[1]) {
 329                ret = request_irq(fsl_lbc_ctrl_dev->irq[1], fsl_lbc_ctrl_irq,
 330                                IRQF_SHARED, "fsl-lbc-err", fsl_lbc_ctrl_dev);
 331                if (ret) {
 332                        dev_err(&dev->dev, "failed to install irq (%d)\n",
 333                                        fsl_lbc_ctrl_dev->irq[1]);
 334                        ret = fsl_lbc_ctrl_dev->irq[1];
 335                        goto err1;
 336                }
 337        }
 338
 339        /* Enable interrupts for any detected events */
 340        out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE);
 341
 342        return 0;
 343
 344err1:
 345        free_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_dev);
 346err:
 347        iounmap(fsl_lbc_ctrl_dev->regs);
 348        kfree(fsl_lbc_ctrl_dev);
 349        fsl_lbc_ctrl_dev = NULL;
 350        return ret;
 351}
 352
 353#ifdef CONFIG_SUSPEND
 354
 355/* save lbc registers */
 356static int fsl_lbc_syscore_suspend(void)
 357{
 358        struct fsl_lbc_ctrl *ctrl;
 359        struct fsl_lbc_regs __iomem *lbc;
 360
 361        ctrl = fsl_lbc_ctrl_dev;
 362        if (!ctrl)
 363                goto out;
 364
 365        lbc = ctrl->regs;
 366        if (!lbc)
 367                goto out;
 368
 369        ctrl->saved_regs = kmalloc(sizeof(struct fsl_lbc_regs), GFP_KERNEL);
 370        if (!ctrl->saved_regs)
 371                return -ENOMEM;
 372
 373        _memcpy_fromio(ctrl->saved_regs, lbc, sizeof(struct fsl_lbc_regs));
 374
 375out:
 376        return 0;
 377}
 378
 379/* restore lbc registers */
 380static void fsl_lbc_syscore_resume(void)
 381{
 382        struct fsl_lbc_ctrl *ctrl;
 383        struct fsl_lbc_regs __iomem *lbc;
 384
 385        ctrl = fsl_lbc_ctrl_dev;
 386        if (!ctrl)
 387                goto out;
 388
 389        lbc = ctrl->regs;
 390        if (!lbc)
 391                goto out;
 392
 393        if (ctrl->saved_regs) {
 394                _memcpy_toio(lbc, ctrl->saved_regs,
 395                                sizeof(struct fsl_lbc_regs));
 396                kfree(ctrl->saved_regs);
 397                ctrl->saved_regs = NULL;
 398        }
 399
 400out:
 401        return;
 402}
 403#endif /* CONFIG_SUSPEND */
 404
 405static const struct of_device_id fsl_lbc_match[] = {
 406        { .compatible = "fsl,elbc", },
 407        { .compatible = "fsl,pq3-localbus", },
 408        { .compatible = "fsl,pq2-localbus", },
 409        { .compatible = "fsl,pq2pro-localbus", },
 410        {},
 411};
 412
 413#ifdef CONFIG_SUSPEND
 414static struct syscore_ops lbc_syscore_pm_ops = {
 415        .suspend = fsl_lbc_syscore_suspend,
 416        .resume = fsl_lbc_syscore_resume,
 417};
 418#endif
 419
 420static struct platform_driver fsl_lbc_ctrl_driver = {
 421        .driver = {
 422                .name = "fsl-lbc",
 423                .of_match_table = fsl_lbc_match,
 424        },
 425        .probe = fsl_lbc_ctrl_probe,
 426};
 427
 428static int __init fsl_lbc_init(void)
 429{
 430#ifdef CONFIG_SUSPEND
 431        register_syscore_ops(&lbc_syscore_pm_ops);
 432#endif
 433        return platform_driver_register(&fsl_lbc_ctrl_driver);
 434}
 435subsys_initcall(fsl_lbc_init);
 436