| /* Cypress West Bridge API source file (cyasintr.c) |
| ## =========================== |
| ## Copyright (C) 2010 Cypress Semiconductor |
| ## |
| ## This program is free software; you can redistribute it and/or |
| ## modify it under the terms of the GNU General Public License |
| ## as published by the Free Software Foundation; either version 2 |
| ## of the License, or (at your option) any later version. |
| ## |
| ## This program is distributed in the hope that it will be useful, |
| ## but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ## GNU General Public License for more details. |
| ## |
| ## You should have received a copy of the GNU General Public License |
| ## along with this program; if not, write to the Free Software |
| ## Foundation, Inc., 51 Franklin Street, Fifth Floor |
| ## Boston, MA 02110-1301, USA. |
| ## =========================== |
| */ |
| |
| #include "../../include/linux/westbridge/cyashal.h" |
| #include "../../include/linux/westbridge/cyasdevice.h" |
| #include "../../include/linux/westbridge/cyasregs.h" |
| #include "../../include/linux/westbridge/cyaserr.h" |
| |
| extern void cy_as_mail_box_interrupt_handler(cy_as_device *); |
| |
| void |
| cy_as_mcu_interrupt_handler(cy_as_device *dev_p) |
| { |
| /* Read and clear the interrupt. */ |
| uint16_t v; |
| |
| v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_MCU_STAT); |
| v = v; |
| } |
| |
| void |
| cy_as_power_management_interrupt_handler(cy_as_device *dev_p) |
| { |
| uint16_t v; |
| |
| v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PWR_MAGT_STAT); |
| v = v; |
| } |
| |
| void |
| cy_as_pll_lock_loss_interrupt_handler(cy_as_device *dev_p) |
| { |
| uint16_t v; |
| |
| v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_PLL_LOCK_LOSS_STAT); |
| v = v; |
| } |
| |
| uint32_t cy_as_intr_start(cy_as_device *dev_p, cy_bool dmaintr) |
| { |
| uint16_t v; |
| |
| cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE); |
| |
| if (cy_as_device_is_intr_running(dev_p) != 0) |
| return CY_AS_ERROR_ALREADY_RUNNING; |
| |
| v = CY_AS_MEM_P0_INT_MASK_REG_MMCUINT | |
| CY_AS_MEM_P0_INT_MASK_REG_MMBINT | |
| CY_AS_MEM_P0_INT_MASK_REG_MPMINT; |
| |
| if (dmaintr) |
| v |= CY_AS_MEM_P0_INT_MASK_REG_MDRQINT; |
| |
| /* Enable the interrupts of interest */ |
| cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_INT_MASK_REG, v); |
| |
| /* Mark the interrupt module as initialized */ |
| cy_as_device_set_intr_running(dev_p); |
| |
| return CY_AS_ERROR_SUCCESS; |
| } |
| |
| uint32_t cy_as_intr_stop(cy_as_device *dev_p) |
| { |
| cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE); |
| |
| if (cy_as_device_is_intr_running(dev_p) == 0) |
| return CY_AS_ERROR_NOT_RUNNING; |
| |
| cy_as_hal_write_register(dev_p->tag, CY_AS_MEM_P0_INT_MASK_REG, 0); |
| cy_as_device_set_intr_stopped(dev_p); |
| |
| return CY_AS_ERROR_SUCCESS; |
| } |
| |
| void cy_as_intr_service_interrupt(cy_as_hal_device_tag tag) |
| { |
| uint16_t v; |
| cy_as_device *dev_p; |
| |
| dev_p = cy_as_device_find_from_tag(tag); |
| |
| /* |
| * only power management interrupts can occur before the |
| * antioch API setup is complete. if this is a PM interrupt |
| * handle it here; otherwise output a warning message. |
| */ |
| if (dev_p == 0) { |
| v = cy_as_hal_read_register(tag, CY_AS_MEM_P0_INTR_REG); |
| if (v == CY_AS_MEM_P0_INTR_REG_PMINT) { |
| /* Read the PWR_MAGT_STAT register |
| * to clear this interrupt. */ |
| v = cy_as_hal_read_register(tag, |
| CY_AS_MEM_PWR_MAGT_STAT); |
| } else |
| cy_as_hal_print_message("stray antioch " |
| "interrupt detected" |
| ", tag not associated " |
| "with any created device."); |
| return; |
| } |
| |
| /* Make sure we got a valid object from CyAsDeviceFindFromTag */ |
| cy_as_hal_assert(dev_p->sig == CY_AS_DEVICE_HANDLE_SIGNATURE); |
| |
| v = cy_as_hal_read_register(dev_p->tag, CY_AS_MEM_P0_INTR_REG); |
| |
| if (v & CY_AS_MEM_P0_INTR_REG_MCUINT) |
| cy_as_mcu_interrupt_handler(dev_p); |
| |
| if (v & CY_AS_MEM_P0_INTR_REG_PMINT) |
| cy_as_power_management_interrupt_handler(dev_p); |
| |
| if (v & CY_AS_MEM_P0_INTR_REG_PLLLOCKINT) |
| cy_as_pll_lock_loss_interrupt_handler(dev_p); |
| |
| /* If the interrupt module is not running, no mailbox |
| * interrupts are expected from the west bridge. */ |
| if (cy_as_device_is_intr_running(dev_p) == 0) |
| return; |
| |
| if (v & CY_AS_MEM_P0_INTR_REG_MBINT) |
| cy_as_mail_box_interrupt_handler(dev_p); |
| } |