| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. |
|---|
| 2 | | - * |
|---|
| 3 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 4 | | - * it under the terms of the GNU General Public License version 2 and |
|---|
| 5 | | - * only version 2 as published by the Free Software Foundation. |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 8 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 9 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 10 | | - * GNU General Public License for more details. |
|---|
| 11 | 3 | */ |
|---|
| 12 | 4 | |
|---|
| 13 | 5 | #include <linux/bitops.h> |
|---|
| .. | .. |
|---|
| 170 | 162 | /** |
|---|
| 171 | 163 | * AD4 interrupt status bit definitions |
|---|
| 172 | 164 | */ |
|---|
| 173 | | -#define DPU_INTR_BRIGHTPR_UPDATED BIT(4) |
|---|
| 174 | | -#define DPU_INTR_DARKENH_UPDATED BIT(3) |
|---|
| 175 | | -#define DPU_INTR_STREN_OUTROI_UPDATED BIT(2) |
|---|
| 176 | | -#define DPU_INTR_STREN_INROI_UPDATED BIT(1) |
|---|
| 177 | 165 | #define DPU_INTR_BACKLIGHT_UPDATED BIT(0) |
|---|
| 178 | 166 | /** |
|---|
| 179 | 167 | * struct dpu_intr_reg - array of DPU register sets |
|---|
| .. | .. |
|---|
| 782 | 770 | return -EINVAL; |
|---|
| 783 | 771 | } |
|---|
| 784 | 772 | |
|---|
| 785 | | -static void dpu_hw_intr_set_mask(struct dpu_hw_intr *intr, uint32_t reg_off, |
|---|
| 786 | | - uint32_t mask) |
|---|
| 787 | | -{ |
|---|
| 788 | | - if (!intr) |
|---|
| 789 | | - return; |
|---|
| 790 | | - |
|---|
| 791 | | - DPU_REG_WRITE(&intr->hw, reg_off, mask); |
|---|
| 792 | | - |
|---|
| 793 | | - /* ensure register writes go through */ |
|---|
| 794 | | - wmb(); |
|---|
| 795 | | -} |
|---|
| 796 | | - |
|---|
| 797 | 773 | static void dpu_hw_intr_dispatch_irq(struct dpu_hw_intr *intr, |
|---|
| 798 | 774 | void (*cbfunc)(void *, int), |
|---|
| 799 | 775 | void *arg) |
|---|
| .. | .. |
|---|
| 824 | 800 | start_idx = reg_idx * 32; |
|---|
| 825 | 801 | end_idx = start_idx + 32; |
|---|
| 826 | 802 | |
|---|
| 827 | | - if (start_idx >= ARRAY_SIZE(dpu_irq_map) || |
|---|
| 828 | | - end_idx > ARRAY_SIZE(dpu_irq_map)) |
|---|
| 803 | + if (!test_bit(reg_idx, &intr->irq_mask) || |
|---|
| 804 | + start_idx >= ARRAY_SIZE(dpu_irq_map)) |
|---|
| 829 | 805 | continue; |
|---|
| 830 | 806 | |
|---|
| 831 | 807 | /* |
|---|
| .. | .. |
|---|
| 979 | 955 | if (!intr) |
|---|
| 980 | 956 | return -EINVAL; |
|---|
| 981 | 957 | |
|---|
| 982 | | - for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) |
|---|
| 983 | | - DPU_REG_WRITE(&intr->hw, dpu_intr_set[i].clr_off, 0xffffffff); |
|---|
| 958 | + for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { |
|---|
| 959 | + if (test_bit(i, &intr->irq_mask)) |
|---|
| 960 | + DPU_REG_WRITE(&intr->hw, |
|---|
| 961 | + dpu_intr_set[i].clr_off, 0xffffffff); |
|---|
| 962 | + } |
|---|
| 984 | 963 | |
|---|
| 985 | 964 | /* ensure register writes go through */ |
|---|
| 986 | 965 | wmb(); |
|---|
| .. | .. |
|---|
| 995 | 974 | if (!intr) |
|---|
| 996 | 975 | return -EINVAL; |
|---|
| 997 | 976 | |
|---|
| 998 | | - for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) |
|---|
| 999 | | - DPU_REG_WRITE(&intr->hw, dpu_intr_set[i].en_off, 0x00000000); |
|---|
| 977 | + for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { |
|---|
| 978 | + if (test_bit(i, &intr->irq_mask)) |
|---|
| 979 | + DPU_REG_WRITE(&intr->hw, |
|---|
| 980 | + dpu_intr_set[i].en_off, 0x00000000); |
|---|
| 981 | + } |
|---|
| 1000 | 982 | |
|---|
| 1001 | 983 | /* ensure register writes go through */ |
|---|
| 1002 | 984 | wmb(); |
|---|
| 1003 | | - |
|---|
| 1004 | | - return 0; |
|---|
| 1005 | | -} |
|---|
| 1006 | | - |
|---|
| 1007 | | -static int dpu_hw_intr_get_valid_interrupts(struct dpu_hw_intr *intr, |
|---|
| 1008 | | - uint32_t *mask) |
|---|
| 1009 | | -{ |
|---|
| 1010 | | - if (!intr || !mask) |
|---|
| 1011 | | - return -EINVAL; |
|---|
| 1012 | | - |
|---|
| 1013 | | - *mask = IRQ_SOURCE_MDP | IRQ_SOURCE_DSI0 | IRQ_SOURCE_DSI1 |
|---|
| 1014 | | - | IRQ_SOURCE_HDMI | IRQ_SOURCE_EDP; |
|---|
| 1015 | 985 | |
|---|
| 1016 | 986 | return 0; |
|---|
| 1017 | 987 | } |
|---|
| .. | .. |
|---|
| 1027 | 997 | |
|---|
| 1028 | 998 | spin_lock_irqsave(&intr->irq_lock, irq_flags); |
|---|
| 1029 | 999 | for (i = 0; i < ARRAY_SIZE(dpu_intr_set); i++) { |
|---|
| 1000 | + if (!test_bit(i, &intr->irq_mask)) |
|---|
| 1001 | + continue; |
|---|
| 1002 | + |
|---|
| 1030 | 1003 | /* Read interrupt status */ |
|---|
| 1031 | 1004 | intr->save_irq_status[i] = DPU_REG_READ(&intr->hw, |
|---|
| 1032 | 1005 | dpu_intr_set[i].status_off); |
|---|
| .. | .. |
|---|
| 1065 | 1038 | wmb(); |
|---|
| 1066 | 1039 | } |
|---|
| 1067 | 1040 | |
|---|
| 1068 | | -static void dpu_hw_intr_clear_interrupt_status(struct dpu_hw_intr *intr, |
|---|
| 1069 | | - int irq_idx) |
|---|
| 1070 | | -{ |
|---|
| 1071 | | - unsigned long irq_flags; |
|---|
| 1072 | | - |
|---|
| 1073 | | - if (!intr) |
|---|
| 1074 | | - return; |
|---|
| 1075 | | - |
|---|
| 1076 | | - spin_lock_irqsave(&intr->irq_lock, irq_flags); |
|---|
| 1077 | | - dpu_hw_intr_clear_intr_status_nolock(intr, irq_idx); |
|---|
| 1078 | | - spin_unlock_irqrestore(&intr->irq_lock, irq_flags); |
|---|
| 1079 | | -} |
|---|
| 1080 | | - |
|---|
| 1081 | 1041 | static u32 dpu_hw_intr_get_interrupt_status(struct dpu_hw_intr *intr, |
|---|
| 1082 | 1042 | int irq_idx, bool clear) |
|---|
| 1083 | 1043 | { |
|---|
| .. | .. |
|---|
| 1113 | 1073 | |
|---|
| 1114 | 1074 | static void __setup_intr_ops(struct dpu_hw_intr_ops *ops) |
|---|
| 1115 | 1075 | { |
|---|
| 1116 | | - ops->set_mask = dpu_hw_intr_set_mask; |
|---|
| 1117 | 1076 | ops->irq_idx_lookup = dpu_hw_intr_irqidx_lookup; |
|---|
| 1118 | 1077 | ops->enable_irq = dpu_hw_intr_enable_irq; |
|---|
| 1119 | 1078 | ops->disable_irq = dpu_hw_intr_disable_irq; |
|---|
| 1120 | 1079 | ops->dispatch_irqs = dpu_hw_intr_dispatch_irq; |
|---|
| 1121 | 1080 | ops->clear_all_irqs = dpu_hw_intr_clear_irqs; |
|---|
| 1122 | 1081 | ops->disable_all_irqs = dpu_hw_intr_disable_irqs; |
|---|
| 1123 | | - ops->get_valid_interrupts = dpu_hw_intr_get_valid_interrupts; |
|---|
| 1124 | 1082 | ops->get_interrupt_statuses = dpu_hw_intr_get_interrupt_statuses; |
|---|
| 1125 | | - ops->clear_interrupt_status = dpu_hw_intr_clear_interrupt_status; |
|---|
| 1126 | 1083 | ops->clear_intr_status_nolock = dpu_hw_intr_clear_intr_status_nolock; |
|---|
| 1127 | 1084 | ops->get_interrupt_status = dpu_hw_intr_get_interrupt_status; |
|---|
| 1128 | 1085 | } |
|---|
| .. | .. |
|---|
| 1167 | 1124 | return ERR_PTR(-ENOMEM); |
|---|
| 1168 | 1125 | } |
|---|
| 1169 | 1126 | |
|---|
| 1127 | + intr->irq_mask = m->mdss_irqs; |
|---|
| 1170 | 1128 | spin_lock_init(&intr->irq_lock); |
|---|
| 1171 | 1129 | |
|---|
| 1172 | 1130 | return intr; |
|---|