linux/drivers/dma/ipu/ipu_irq.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2008
   3 * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License version 2 as
   7 * published by the Free Software Foundation.
   8 */
   9
  10#include <linux/init.h>
  11#include <linux/err.h>
  12#include <linux/spinlock.h>
  13#include <linux/delay.h>
  14#include <linux/clk.h>
  15#include <linux/irq.h>
  16#include <linux/io.h>
  17
  18#include <mach/ipu.h>
  19
  20#include "ipu_intern.h"
  21
  22/*
  23 * Register read / write - shall be inlined by the compiler
  24 */
  25static u32 ipu_read_reg(struct ipu *ipu, unsigned long reg)
  26{
  27        return __raw_readl(ipu->reg_ipu + reg);
  28}
  29
  30static void ipu_write_reg(struct ipu *ipu, u32 value, unsigned long reg)
  31{
  32        __raw_writel(value, ipu->reg_ipu + reg);
  33}
  34
  35
  36/*
  37 * IPU IRQ chip driver
  38 */
  39
  40#define IPU_IRQ_NR_FN_BANKS 3
  41#define IPU_IRQ_NR_ERR_BANKS 2
  42#define IPU_IRQ_NR_BANKS (IPU_IRQ_NR_FN_BANKS + IPU_IRQ_NR_ERR_BANKS)
  43
  44struct ipu_irq_bank {
  45        unsigned int    control;
  46        unsigned int    status;
  47        spinlock_t      lock;
  48        struct ipu      *ipu;
  49};
  50
  51static struct ipu_irq_bank irq_bank[IPU_IRQ_NR_BANKS] = {
  52        /* 3 groups of functional interrupts */
  53        {
  54                .control        = IPU_INT_CTRL_1,
  55                .status         = IPU_INT_STAT_1,
  56        }, {
  57                .control        = IPU_INT_CTRL_2,
  58                .status         = IPU_INT_STAT_2,
  59        }, {
  60                .control        = IPU_INT_CTRL_3,
  61                .status         = IPU_INT_STAT_3,
  62        },
  63        /* 2 groups of error interrupts */
  64        {
  65                .control        = IPU_INT_CTRL_4,
  66                .status         = IPU_INT_STAT_4,
  67        }, {
  68                .control        = IPU_INT_CTRL_5,
  69                .status         = IPU_INT_STAT_5,
  70        },
  71};
  72
  73struct ipu_irq_map {
  74        unsigned int            irq;
  75        int                     source;
  76        struct ipu_irq_bank     *bank;
  77        struct ipu              *ipu;
  78};
  79
  80static struct ipu_irq_map irq_map[CONFIG_MX3_IPU_IRQS];
  81/* Protects allocations from the above array of maps */
  82static DEFINE_MUTEX(map_lock);
  83/* Protects register accesses and individual mappings */
  84static DEFINE_SPINLOCK(bank_lock);
  85
  86static struct ipu_irq_map *src2map(unsigned int src)
  87{
  88        int i;
  89
  90        for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++)
  91                if (irq_map[i].source == src)
  92                        return irq_map + i;
  93
  94        return NULL;
  95}
  96
  97static void ipu_irq_unmask(unsigned int irq)
  98{
  99        struct ipu_irq_map *map = get_irq_chip_data(irq);
 100        struct ipu_irq_bank *bank;
 101        uint32_t reg;
 102        unsigned long lock_flags;
 103
 104        spin_lock_irqsave(&bank_lock, lock_flags);
 105
 106        bank = map->bank;
 107        if (!bank) {
 108                spin_unlock_irqrestore(&bank_lock, lock_flags);
 109                pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq);
 110                return;
 111        }
 112
 113        reg = ipu_read_reg(bank->ipu, bank->control);
 114        reg |= (1UL << (map->source & 31));
 115        ipu_write_reg(bank->ipu, reg, bank->control);
 116
 117        spin_unlock_irqrestore(&bank_lock, lock_flags);
 118}
 119
 120static void ipu_irq_mask(unsigned int irq)
 121{
 122        struct ipu_irq_map *map = get_irq_chip_data(irq);
 123        struct ipu_irq_bank *bank;
 124        uint32_t reg;
 125        unsigned long lock_flags;
 126
 127        spin_lock_irqsave(&bank_lock, lock_flags);
 128
 129        bank = map->bank;
 130        if (!bank) {
 131                spin_unlock_irqrestore(&bank_lock, lock_flags);
 132                pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq);
 133                return;
 134        }
 135
 136        reg = ipu_read_reg(bank->ipu, bank->control);
 137        reg &= ~(1UL << (map->source & 31));
 138        ipu_write_reg(bank->ipu, reg, bank->control);
 139
 140        spin_unlock_irqrestore(&bank_lock, lock_flags);
 141}
 142
 143static void ipu_irq_ack(unsigned int irq)
 144{
 145        struct ipu_irq_map *map = get_irq_chip_data(irq);
 146        struct ipu_irq_bank *bank;
 147        unsigned long lock_flags;
 148
 149        spin_lock_irqsave(&bank_lock, lock_flags);
 150
 151        bank = map->bank;
 152        if (!bank) {
 153                spin_unlock_irqrestore(&bank_lock, lock_flags);
 154                pr_err("IPU: %s(%u) - unmapped!\n", __func__, irq);
 155                return;
 156        }
 157
 158        ipu_write_reg(bank->ipu, 1UL << (map->source & 31), bank->status);
 159        spin_unlock_irqrestore(&bank_lock, lock_flags);
 160}
 161
 162/**
 163 * ipu_irq_status() - returns the current interrupt status of the specified IRQ.
 164 * @irq:        interrupt line to get status for.
 165 * @return:     true if the interrupt is pending/asserted or false if the
 166 *              interrupt is not pending.
 167 */
 168bool ipu_irq_status(unsigned int irq)
 169{
 170        struct ipu_irq_map *map = get_irq_chip_data(irq);
 171        struct ipu_irq_bank *bank;
 172        unsigned long lock_flags;
 173        bool ret;
 174
 175        spin_lock_irqsave(&bank_lock, lock_flags);
 176        bank = map->bank;
 177        ret = bank && ipu_read_reg(bank->ipu, bank->status) &
 178                (1UL << (map->source & 31));
 179        spin_unlock_irqrestore(&bank_lock, lock_flags);
 180
 181        return ret;
 182}
 183
 184/**
 185 * ipu_irq_map() - map an IPU interrupt source to an IRQ number
 186 * @source:     interrupt source bit position (see below)
 187 * @return:     mapped IRQ number or negative error code
 188 *
 189 * The source parameter has to be explained further. On i.MX31 IPU has 137 IRQ
 190 * sources, they are broken down in 5 32-bit registers, like 32, 32, 24, 32, 17.
 191 * However, the source argument of this function is not the sequence number of
 192 * the possible IRQ, but rather its bit position. So, first interrupt in fourth
 193 * register has source number 96, and not 88. This makes calculations easier,
 194 * and also provides forward compatibility with any future IPU implementations
 195 * with any interrupt bit assignments.
 196 */
 197int ipu_irq_map(unsigned int source)
 198{
 199        int i, ret = -ENOMEM;
 200        struct ipu_irq_map *map;
 201
 202        might_sleep();
 203
 204        mutex_lock(&map_lock);
 205        map = src2map(source);
 206        if (map) {
 207                pr_err("IPU: Source %u already mapped to IRQ %u\n", source, map->irq);
 208                ret = -EBUSY;
 209                goto out;
 210        }
 211
 212        for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
 213                if (irq_map[i].source < 0) {
 214                        unsigned long lock_flags;
 215
 216                        spin_lock_irqsave(&bank_lock, lock_flags);
 217                        irq_map[i].source = source;
 218                        irq_map[i].bank = irq_bank + source / 32;
 219                        spin_unlock_irqrestore(&bank_lock, lock_flags);
 220
 221                        ret = irq_map[i].irq;
 222                        pr_debug("IPU: mapped source %u to IRQ %u\n",
 223                                 source, ret);
 224                        break;
 225                }
 226        }
 227out:
 228        mutex_unlock(&map_lock);
 229
 230        if (ret < 0)
 231                pr_err("IPU: couldn't map source %u: %d\n", source, ret);
 232
 233        return ret;
 234}
 235
 236/**
 237 * ipu_irq_map() - map an IPU interrupt source to an IRQ number
 238 * @source:     interrupt source bit position (see ipu_irq_map())
 239 * @return:     0 or negative error code
 240 */
 241int ipu_irq_unmap(unsigned int source)
 242{
 243        int i, ret = -EINVAL;
 244
 245        might_sleep();
 246
 247        mutex_lock(&map_lock);
 248        for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
 249                if (irq_map[i].source == source) {
 250                        unsigned long lock_flags;
 251
 252                        pr_debug("IPU: unmapped source %u from IRQ %u\n",
 253                                 source, irq_map[i].irq);
 254
 255                        spin_lock_irqsave(&bank_lock, lock_flags);
 256                        irq_map[i].source = -EINVAL;
 257                        irq_map[i].bank = NULL;
 258                        spin_unlock_irqrestore(&bank_lock, lock_flags);
 259
 260                        ret = 0;
 261                        break;
 262                }
 263        }
 264        mutex_unlock(&map_lock);
 265
 266        return ret;
 267}
 268
 269/* Chained IRQ handler for IPU error interrupt */
 270static void ipu_irq_err(unsigned int irq, struct irq_desc *desc)
 271{
 272        struct ipu *ipu = get_irq_data(irq);
 273        u32 status;
 274        int i, line;
 275
 276        for (i = IPU_IRQ_NR_FN_BANKS; i < IPU_IRQ_NR_BANKS; i++) {
 277                struct ipu_irq_bank *bank = irq_bank + i;
 278
 279                spin_lock(&bank_lock);
 280                status = ipu_read_reg(ipu, bank->status);
 281                /*
 282                 * Don't think we have to clear all interrupts here, they will
 283                 * be acked by ->handle_irq() (handle_level_irq). However, we
 284                 * might want to clear unhandled interrupts after the loop...
 285                 */
 286                status &= ipu_read_reg(ipu, bank->control);
 287                spin_unlock(&bank_lock);
 288                while ((line = ffs(status))) {
 289                        struct ipu_irq_map *map;
 290
 291                        line--;
 292                        status &= ~(1UL << line);
 293
 294                        spin_lock(&bank_lock);
 295                        map = src2map(32 * i + line);
 296                        if (map)
 297                                irq = map->irq;
 298                        spin_unlock(&bank_lock);
 299
 300                        if (!map) {
 301                                pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
 302                                       line, i);
 303                                continue;
 304                        }
 305                        generic_handle_irq(irq);
 306                }
 307        }
 308}
 309
 310/* Chained IRQ handler for IPU function interrupt */
 311static void ipu_irq_fn(unsigned int irq, struct irq_desc *desc)
 312{
 313        struct ipu *ipu = get_irq_data(irq);
 314        u32 status;
 315        int i, line;
 316
 317        for (i = 0; i < IPU_IRQ_NR_FN_BANKS; i++) {
 318                struct ipu_irq_bank *bank = irq_bank + i;
 319
 320                spin_lock(&bank_lock);
 321                status = ipu_read_reg(ipu, bank->status);
 322                /* Not clearing all interrupts, see above */
 323                status &= ipu_read_reg(ipu, bank->control);
 324                spin_unlock(&bank_lock);
 325                while ((line = ffs(status))) {
 326                        struct ipu_irq_map *map;
 327
 328                        line--;
 329                        status &= ~(1UL << line);
 330
 331                        spin_lock(&bank_lock);
 332                        map = src2map(32 * i + line);
 333                        if (map)
 334                                irq = map->irq;
 335                        spin_unlock(&bank_lock);
 336
 337                        if (!map) {
 338                                pr_err("IPU: Interrupt on unmapped source %u bank %d\n",
 339                                       line, i);
 340                                continue;
 341                        }
 342                        generic_handle_irq(irq);
 343                }
 344        }
 345}
 346
 347static struct irq_chip ipu_irq_chip = {
 348        .name   = "ipu_irq",
 349        .ack    = ipu_irq_ack,
 350        .mask   = ipu_irq_mask,
 351        .unmask = ipu_irq_unmask,
 352};
 353
 354/* Install the IRQ handler */
 355int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev)
 356{
 357        struct ipu_platform_data *pdata = dev->dev.platform_data;
 358        unsigned int irq, irq_base, i;
 359
 360        irq_base = pdata->irq_base;
 361
 362        for (i = 0; i < IPU_IRQ_NR_BANKS; i++)
 363                irq_bank[i].ipu = ipu;
 364
 365        for (i = 0; i < CONFIG_MX3_IPU_IRQS; i++) {
 366                int ret;
 367
 368                irq = irq_base + i;
 369                ret = set_irq_chip(irq, &ipu_irq_chip);
 370                if (ret < 0)
 371                        return ret;
 372                ret = set_irq_chip_data(irq, irq_map + i);
 373                if (ret < 0)
 374                        return ret;
 375                irq_map[i].ipu = ipu;
 376                irq_map[i].irq = irq;
 377                irq_map[i].source = -EINVAL;
 378                set_irq_handler(irq, handle_level_irq);
 379#ifdef CONFIG_ARM
 380                set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 381#endif
 382        }
 383
 384        set_irq_data(ipu->irq_fn, ipu);
 385        set_irq_chained_handler(ipu->irq_fn, ipu_irq_fn);
 386
 387        set_irq_data(ipu->irq_err, ipu);
 388        set_irq_chained_handler(ipu->irq_err, ipu_irq_err);
 389
 390        return 0;
 391}
 392
 393void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev)
 394{
 395        struct ipu_platform_data *pdata = dev->dev.platform_data;
 396        unsigned int irq, irq_base;
 397
 398        irq_base = pdata->irq_base;
 399
 400        set_irq_chained_handler(ipu->irq_fn, NULL);
 401        set_irq_data(ipu->irq_fn, NULL);
 402
 403        set_irq_chained_handler(ipu->irq_err, NULL);
 404        set_irq_data(ipu->irq_err, NULL);
 405
 406        for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) {
 407#ifdef CONFIG_ARM
 408                set_irq_flags(irq, 0);
 409#endif
 410                set_irq_chip(irq, NULL);
 411                set_irq_chip_data(irq, NULL);
 412        }
 413}
 414