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