blob: 6d4e4f95a4262f71a8bbbd0e865259fe778b763c [file] [log] [blame]
/* Copyright (c) 2007-2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*/
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/interrupt.h>
#include "mdss_mdp.h"
struct mdss_hw *mdss_irq_handlers[MDSS_MAX_HW_BLK];
static DEFINE_SPINLOCK(mdss_lock);
int mdss_register_irq(struct mdss_hw *hw)
{
unsigned long irq_flags;
u32 ndx_bit;
if (!hw || hw->hw_ndx >= MDSS_MAX_HW_BLK)
return -EINVAL;
ndx_bit = BIT(hw->hw_ndx);
spin_lock_irqsave(&mdss_lock, irq_flags);
if (!mdss_irq_handlers[hw->hw_ndx])
mdss_irq_handlers[hw->hw_ndx] = hw;
else
pr_err("panel %d's irq at %p is already registered\n",
hw->hw_ndx, hw->irq_handler);
spin_unlock_irqrestore(&mdss_lock, irq_flags);
return 0;
}
void mdss_enable_irq(struct mdss_hw *hw)
{
unsigned long irq_flags;
u32 ndx_bit;
if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
return;
if (!mdss_irq_handlers[hw->hw_ndx]) {
pr_err("failed. First register the irq then enable it.\n");
return;
}
ndx_bit = BIT(hw->hw_ndx);
pr_debug("Enable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
hw->irq_info->irq_ena, hw->irq_info->irq_mask);
spin_lock_irqsave(&mdss_lock, irq_flags);
if (hw->irq_info->irq_mask & ndx_bit) {
pr_debug("MDSS HW ndx=%d is already set, mask=%x\n",
hw->hw_ndx, hw->irq_info->irq_mask);
} else {
hw->irq_info->irq_mask |= ndx_bit;
if (!hw->irq_info->irq_ena) {
hw->irq_info->irq_ena = true;
enable_irq(hw->irq_info->irq);
}
}
spin_unlock_irqrestore(&mdss_lock, irq_flags);
}
void mdss_disable_irq(struct mdss_hw *hw)
{
unsigned long irq_flags;
u32 ndx_bit;
if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
return;
ndx_bit = BIT(hw->hw_ndx);
pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
hw->irq_info->irq_ena, hw->irq_info->irq_mask);
spin_lock_irqsave(&mdss_lock, irq_flags);
if (!(hw->irq_info->irq_mask & ndx_bit)) {
pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx);
} else {
hw->irq_info->irq_mask &= ~ndx_bit;
if (hw->irq_info->irq_mask == 0) {
hw->irq_info->irq_ena = false;
disable_irq_nosync(hw->irq_info->irq);
}
}
spin_unlock_irqrestore(&mdss_lock, irq_flags);
}
/* called from interrupt context */
void mdss_disable_irq_nosync(struct mdss_hw *hw)
{
u32 ndx_bit;
if (hw->hw_ndx >= MDSS_MAX_HW_BLK)
return;
ndx_bit = BIT(hw->hw_ndx);
pr_debug("Disable HW=%d irq ena=%d mask=%x\n", hw->hw_ndx,
hw->irq_info->irq_ena, hw->irq_info->irq_mask);
spin_lock(&mdss_lock);
if (!(hw->irq_info->irq_mask & ndx_bit)) {
pr_warn("MDSS HW ndx=%d is NOT set\n", hw->hw_ndx);
} else {
hw->irq_info->irq_mask &= ~ndx_bit;
if (hw->irq_info->irq_mask == 0) {
hw->irq_info->irq_ena = false;
disable_irq_nosync(hw->irq_info->irq);
}
}
spin_unlock(&mdss_lock);
}
int mdss_irq_dispatch(u32 hw_ndx, int irq, void *ptr)
{
struct mdss_hw *hw;
int rc = -ENODEV;
spin_lock(&mdss_lock);
hw = mdss_irq_handlers[hw_ndx];
spin_unlock(&mdss_lock);
if (hw)
rc = hw->irq_handler(irq, hw->ptr);
return rc;
}
struct mdss_util_intf mdss_util = {
.register_irq = mdss_register_irq,
.enable_irq = mdss_enable_irq,
.disable_irq = mdss_disable_irq,
.disable_irq_nosync = mdss_disable_irq_nosync,
.irq_dispatch = mdss_irq_dispatch,
.get_iommu_domain = NULL,
.iommu_attached = NULL,
.iommu_ctrl = NULL,
.bus_bandwidth_ctrl = NULL,
.bus_scale_set_quota = NULL,
.panel_intf_type = NULL,
.mdp_probe_done = false
};
struct mdss_util_intf *mdss_get_util_intf()
{
return &mdss_util;
}
EXPORT_SYMBOL(mdss_get_util_intf);