linux/drivers/staging/media/atomisp/pci/atomisp2/css2400/hive_isp_css_common/host/irq.c
<<
>>
Prefs
   1/*
   2 * Support for Intel Camera Imaging ISP subsystem.
   3 * Copyright (c) 2010-2015, Intel Corporation.
   4 *
   5 * This program is free software; you can redistribute it and/or modify it
   6 * under the terms and conditions of the GNU General Public License,
   7 * version 2, as published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope it will be useful, but WITHOUT
  10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  12 * more details.
  13 */
  14
  15#include "assert_support.h"
  16#include "irq.h"
  17
  18#ifndef __INLINE_GP_DEVICE__
  19#define __INLINE_GP_DEVICE__
  20#endif
  21#include "gp_device.h"  /* _REG_GP_IRQ_REQUEST_ADDR */
  22
  23#include "platform_support.h"                   /* hrt_sleep() */
  24
  25static inline void irq_wait_for_write_complete(
  26        const irq_ID_t          ID);
  27
  28static inline bool any_irq_channel_enabled(
  29        const irq_ID_t                          ID);
  30
  31static inline irq_ID_t virq_get_irq_id(
  32        const virq_id_t         irq_ID,
  33        unsigned int            *channel_ID);
  34
  35#ifndef __INLINE_IRQ__
  36#include "irq_private.h"
  37#endif /* __INLINE_IRQ__ */
  38
  39static unsigned short IRQ_N_CHANNEL[N_IRQ_ID] = {
  40        IRQ0_ID_N_CHANNEL,
  41        IRQ1_ID_N_CHANNEL,
  42        IRQ2_ID_N_CHANNEL,
  43        IRQ3_ID_N_CHANNEL};
  44
  45static unsigned short IRQ_N_ID_OFFSET[N_IRQ_ID + 1] = {
  46        IRQ0_ID_OFFSET,
  47        IRQ1_ID_OFFSET,
  48        IRQ2_ID_OFFSET,
  49        IRQ3_ID_OFFSET,
  50        IRQ_END_OFFSET};
  51
  52static virq_id_t IRQ_NESTING_ID[N_IRQ_ID] = {
  53        N_virq_id,
  54        virq_ifmt,
  55        virq_isys,
  56        virq_isel};
  57
  58void irq_clear_all(
  59        const irq_ID_t                          ID)
  60{
  61        hrt_data        mask = 0xFFFFFFFF;
  62
  63        assert(ID < N_IRQ_ID);
  64        assert(IRQ_N_CHANNEL[ID] <= HRT_DATA_WIDTH);
  65
  66        if (IRQ_N_CHANNEL[ID] < HRT_DATA_WIDTH) {
  67                mask = ~((~(hrt_data)0)>>IRQ_N_CHANNEL[ID]);
  68        }
  69
  70        irq_reg_store(ID,
  71                _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, mask);
  72        return;
  73}
  74
  75/*
  76 * Do we want the user to be able to set the signalling method ?
  77 */
  78void irq_enable_channel(
  79        const irq_ID_t                          ID,
  80    const unsigned int                  irq_id)
  81{
  82        unsigned int mask = irq_reg_load(ID,
  83                _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
  84        unsigned int enable = irq_reg_load(ID,
  85                _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
  86        unsigned int edge_in = irq_reg_load(ID,
  87                _HRT_IRQ_CONTROLLER_EDGE_REG_IDX);
  88        unsigned int me = 1U << irq_id;
  89
  90        assert(ID < N_IRQ_ID);
  91        assert(irq_id < IRQ_N_CHANNEL[ID]);
  92
  93        mask |= me;
  94        enable |= me;
  95        edge_in |= me;  /* rising edge */
  96
  97/* to avoid mishaps configuration must follow the following order */
  98
  99/* mask this interrupt */
 100        irq_reg_store(ID,
 101                _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask & ~me);
 102/* rising edge at input */
 103        irq_reg_store(ID,
 104                _HRT_IRQ_CONTROLLER_EDGE_REG_IDX, edge_in);
 105/* enable interrupt to output */
 106        irq_reg_store(ID,
 107                _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX, enable);
 108/* clear current irq only */
 109        irq_reg_store(ID,
 110                _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, me);
 111/* unmask interrupt from input */
 112        irq_reg_store(ID,
 113                _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask);
 114
 115        irq_wait_for_write_complete(ID);
 116
 117        return;
 118}
 119
 120void irq_enable_pulse(
 121        const irq_ID_t  ID,
 122        bool                    pulse)
 123{
 124        unsigned int edge_out = 0x0;
 125
 126        if (pulse) {
 127                edge_out = 0xffffffff;
 128        }
 129        /* output is given as edge, not pulse */
 130        irq_reg_store(ID,
 131                _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX, edge_out);
 132        return;
 133}
 134
 135void irq_disable_channel(
 136        const irq_ID_t                          ID,
 137        const unsigned int                      irq_id)
 138{
 139        unsigned int mask = irq_reg_load(ID,
 140                _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
 141        unsigned int enable = irq_reg_load(ID,
 142                _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
 143        unsigned int me = 1U << irq_id;
 144
 145        assert(ID < N_IRQ_ID);
 146        assert(irq_id < IRQ_N_CHANNEL[ID]);
 147
 148        mask &= ~me;
 149        enable &= ~me;
 150
 151/* enable interrupt to output */
 152        irq_reg_store(ID,
 153                _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX, enable);
 154/* unmask interrupt from input */
 155        irq_reg_store(ID,
 156                _HRT_IRQ_CONTROLLER_MASK_REG_IDX, mask);
 157/* clear current irq only */
 158        irq_reg_store(ID,
 159                _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, me);
 160
 161        irq_wait_for_write_complete(ID);
 162
 163        return;
 164}
 165
 166enum hrt_isp_css_irq_status irq_get_channel_id(
 167        const irq_ID_t                          ID,
 168        unsigned int                            *irq_id)
 169{
 170        unsigned int irq_status = irq_reg_load(ID,
 171                _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
 172        unsigned int idx;
 173        enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_success;
 174
 175        assert(ID < N_IRQ_ID);
 176        assert(irq_id != NULL);
 177
 178/* find the first irq bit */
 179        for (idx = 0; idx < IRQ_N_CHANNEL[ID]; idx++) {
 180                if (irq_status & (1U << idx))
 181                        break;
 182        }
 183        if (idx == IRQ_N_CHANNEL[ID])
 184                return hrt_isp_css_irq_status_error;
 185
 186/* now check whether there are more bits set */
 187        if (irq_status != (1U << idx))
 188                status = hrt_isp_css_irq_status_more_irqs;
 189
 190        irq_reg_store(ID,
 191                _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << idx);
 192
 193        irq_wait_for_write_complete(ID);
 194
 195        if (irq_id != NULL)
 196                *irq_id = (unsigned int)idx;
 197
 198        return status;
 199}
 200
 201static const hrt_address IRQ_REQUEST_ADDR[N_IRQ_SW_CHANNEL_ID] = {
 202        _REG_GP_IRQ_REQUEST0_ADDR,
 203        _REG_GP_IRQ_REQUEST1_ADDR};
 204
 205void irq_raise(
 206        const irq_ID_t                          ID,
 207        const irq_sw_channel_id_t       irq_id)
 208{
 209        hrt_address             addr;
 210
 211        OP___assert(ID == IRQ0_ID);
 212        OP___assert(IRQ_BASE[ID] != (hrt_address)-1);
 213        OP___assert(irq_id < N_IRQ_SW_CHANNEL_ID);
 214
 215        (void)ID;
 216
 217        addr = IRQ_REQUEST_ADDR[irq_id];
 218/* The SW IRQ pins are remapped to offset zero */
 219        gp_device_reg_store(GP_DEVICE0_ID,
 220                (unsigned int)addr, 1);
 221        gp_device_reg_store(GP_DEVICE0_ID,
 222                (unsigned int)addr, 0);
 223        return;
 224}
 225
 226void irq_controller_get_state(
 227        const irq_ID_t                          ID,
 228        irq_controller_state_t          *state)
 229{
 230        assert(ID < N_IRQ_ID);
 231        assert(state != NULL);
 232
 233        state->irq_edge = irq_reg_load(ID,
 234                _HRT_IRQ_CONTROLLER_EDGE_REG_IDX);
 235        state->irq_mask = irq_reg_load(ID,
 236                _HRT_IRQ_CONTROLLER_MASK_REG_IDX);
 237        state->irq_status = irq_reg_load(ID,
 238                _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
 239        state->irq_enable = irq_reg_load(ID,
 240                _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
 241        state->irq_level_not_pulse = irq_reg_load(ID,
 242                _HRT_IRQ_CONTROLLER_EDGE_NOT_PULSE_REG_IDX);
 243        return;
 244}
 245
 246bool any_virq_signal(void)
 247{
 248        unsigned int irq_status = irq_reg_load(IRQ0_ID,
 249                _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
 250
 251        return (irq_status != 0);
 252}
 253
 254void cnd_virq_enable_channel(
 255        const virq_id_t                         irq_ID,
 256        const bool                                      en)
 257{
 258        irq_ID_t                i;
 259        unsigned int    channel_ID;
 260        irq_ID_t                ID = virq_get_irq_id(irq_ID, &channel_ID);
 261        
 262        assert(ID < N_IRQ_ID);
 263
 264        for (i=IRQ1_ID;i<N_IRQ_ID;i++) {
 265        /* It is not allowed to enable the pin of a nested IRQ directly */
 266                assert(irq_ID != IRQ_NESTING_ID[i]);
 267        }
 268
 269        if (en) {
 270                irq_enable_channel(ID, channel_ID);
 271                if (IRQ_NESTING_ID[ID] != N_virq_id) {
 272/* Single level nesting, otherwise we'd need to recurse */
 273                        irq_enable_channel(IRQ0_ID, IRQ_NESTING_ID[ID]);
 274                }
 275        } else {
 276                irq_disable_channel(ID, channel_ID);
 277                if ((IRQ_NESTING_ID[ID] != N_virq_id) && !any_irq_channel_enabled(ID)) {
 278/* Only disable the top if the nested ones are empty */
 279                        irq_disable_channel(IRQ0_ID, IRQ_NESTING_ID[ID]);
 280                }
 281        }
 282        return;
 283}
 284
 285
 286void virq_clear_all(void)
 287{
 288        irq_ID_t        irq_id;
 289
 290        for (irq_id = (irq_ID_t)0; irq_id < N_IRQ_ID; irq_id++) {
 291                irq_clear_all(irq_id);
 292        }
 293        return;
 294}
 295
 296enum hrt_isp_css_irq_status virq_get_channel_signals(
 297        virq_info_t                                     *irq_info)
 298{
 299        enum hrt_isp_css_irq_status irq_status = hrt_isp_css_irq_status_error;
 300        irq_ID_t ID;
 301
 302        assert(irq_info != NULL);
 303
 304        for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
 305                if (any_irq_channel_enabled(ID)) {
 306                        hrt_data        irq_data = irq_reg_load(ID,
 307                                _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
 308
 309                        if (irq_data != 0) {
 310/* The error condition is an IRQ pulse received with no IRQ status written */
 311                                irq_status = hrt_isp_css_irq_status_success;
 312                        }
 313
 314                        irq_info->irq_status_reg[ID] |= irq_data;
 315
 316                        irq_reg_store(ID,
 317                                _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, irq_data);
 318
 319                        irq_wait_for_write_complete(ID);
 320                }
 321        }
 322
 323        return irq_status;
 324}
 325
 326void virq_clear_info(
 327        virq_info_t                                     *irq_info)
 328{
 329        irq_ID_t ID;
 330
 331        assert(irq_info != NULL);
 332
 333        for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
 334                        irq_info->irq_status_reg[ID] = 0;
 335        }
 336        return;
 337}
 338
 339enum hrt_isp_css_irq_status virq_get_channel_id(
 340        virq_id_t                                       *irq_id)
 341{
 342        unsigned int irq_status = irq_reg_load(IRQ0_ID,
 343                _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
 344        unsigned int idx;
 345        enum hrt_isp_css_irq_status status = hrt_isp_css_irq_status_success;
 346        irq_ID_t ID;
 347
 348        assert(irq_id != NULL);
 349
 350/* find the first irq bit on device 0 */
 351        for (idx = 0; idx < IRQ_N_CHANNEL[IRQ0_ID]; idx++) {
 352                if (irq_status & (1U << idx))
 353                        break;
 354        }
 355
 356        if (idx == IRQ_N_CHANNEL[IRQ0_ID]) {
 357                return hrt_isp_css_irq_status_error;
 358        }
 359
 360/* Check whether there are more bits set on device 0 */
 361        if (irq_status != (1U << idx)) {
 362                status = hrt_isp_css_irq_status_more_irqs;
 363        }
 364
 365/* Check whether we have an IRQ on one of the nested devices */
 366        for (ID = N_IRQ_ID-1 ; ID > (irq_ID_t)0; ID--) {
 367                if (IRQ_NESTING_ID[ID] == (virq_id_t)idx) {
 368                        break;
 369                }
 370        }
 371
 372/* If we have a nested IRQ, load that state, discard the device 0 state */
 373        if (ID != IRQ0_ID) {
 374                irq_status = irq_reg_load(ID,
 375                        _HRT_IRQ_CONTROLLER_STATUS_REG_IDX);
 376/* find the first irq bit on device "id" */
 377                for (idx = 0; idx < IRQ_N_CHANNEL[ID]; idx++) {
 378                        if (irq_status & (1U << idx))
 379                                break;
 380                }
 381
 382                if (idx == IRQ_N_CHANNEL[ID]) {
 383                        return hrt_isp_css_irq_status_error;
 384                }
 385
 386/* Alternatively check whether there are more bits set on this device */
 387                if (irq_status != (1U << idx)) {
 388                        status = hrt_isp_css_irq_status_more_irqs;
 389                } else {
 390/* If this device is empty, clear the state on device 0 */
 391                        irq_reg_store(IRQ0_ID,
 392                                _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << IRQ_NESTING_ID[ID]);
 393                }
 394        } /* if (ID != IRQ0_ID) */
 395
 396/* Here we proceed to clear the IRQ on detected device, if no nested IRQ, this is device 0 */
 397        irq_reg_store(ID,
 398                _HRT_IRQ_CONTROLLER_CLEAR_REG_IDX, 1U << idx);
 399
 400        irq_wait_for_write_complete(ID);
 401
 402        idx += IRQ_N_ID_OFFSET[ID];
 403        if (irq_id != NULL)
 404                *irq_id = (virq_id_t)idx;
 405
 406        return status;
 407}
 408
 409static inline void irq_wait_for_write_complete(
 410        const irq_ID_t          ID)
 411{
 412        assert(ID < N_IRQ_ID);
 413        assert(IRQ_BASE[ID] != (hrt_address)-1);
 414        (void)ia_css_device_load_uint32(IRQ_BASE[ID] +
 415                _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX*sizeof(hrt_data));
 416}
 417
 418static inline bool any_irq_channel_enabled(
 419        const irq_ID_t                          ID)
 420{
 421        hrt_data        en_reg;
 422
 423        assert(ID < N_IRQ_ID);
 424
 425        en_reg = irq_reg_load(ID,
 426                _HRT_IRQ_CONTROLLER_ENABLE_REG_IDX);
 427
 428        return (en_reg != 0);
 429}
 430
 431static inline irq_ID_t virq_get_irq_id(
 432        const virq_id_t         irq_ID,
 433        unsigned int            *channel_ID)
 434{
 435        irq_ID_t ID;
 436
 437        assert(channel_ID != NULL);
 438
 439        for (ID = (irq_ID_t)0 ; ID < N_IRQ_ID; ID++) {
 440                if (irq_ID < IRQ_N_ID_OFFSET[ID + 1]) {
 441                        break;
 442                }
 443        }
 444
 445        *channel_ID = (unsigned int)irq_ID - IRQ_N_ID_OFFSET[ID];
 446
 447        return ID;
 448}
 449