33 * Copyright (C) 2025 Advanced Micro Devices, Inc.
44 */
55
6+ #include <linux/irq.h>
67#include <linux/pm_runtime.h>
78#include <linux/vmalloc.h>
89#include <media/v4l2-ioctl.h>
910
1011#include "isp4.h"
12+ #include "isp4_hw_reg.h"
1113
1214#define ISP4_DRV_NAME "amd_isp_capture"
15+ #define ISP4_FW_RESP_RB_IRQ_STATUS_MASK \
16+ (ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK | \
17+ ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK)
1318
1419static const struct {
1520 const char * name ;
1621 u32 status_mask ;
1722 u32 en_mask ;
1823 u32 ack_mask ;
1924 u32 rb_int_num ;
20- } isp4_irq [] = {
25+ } isp4_irq [ISP4SD_MAX_FW_RESP_STREAM_NUM ] = {
2126 /* The IRQ order is aligned with the isp4_subdev.fw_resp_thread order */
2227 {
2328 .name = "isp_irq_global" ,
29+ .status_mask =
30+ ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK ,
31+ .en_mask = ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK ,
32+ .ack_mask = ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK ,
2433 .rb_int_num = 4 , /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT12 */
2534 },
2635 {
2736 .name = "isp_irq_stream1" ,
37+ .status_mask =
38+ ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK ,
39+ .en_mask = ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK ,
40+ .ack_mask = ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK ,
2841 .rb_int_num = 0 , /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT9 */
2942 },
3043};
3144
45+ void isp4_intr_enable (struct isp4_subdev * isp_subdev , u32 index , bool enable )
46+ {
47+ u32 intr_en ;
48+
49+ /* Synchronize ISP_SYS_INT0_EN writes with the IRQ handler's writes */
50+ spin_lock_irq (& isp_subdev -> irq_lock );
51+ intr_en = isp4hw_rreg (isp_subdev -> mmio , ISP_SYS_INT0_EN );
52+ if (enable )
53+ intr_en |= isp4_irq [index ].en_mask ;
54+ else
55+ intr_en &= ~isp4_irq [index ].en_mask ;
56+
57+ isp4hw_wreg (isp_subdev -> mmio , ISP_SYS_INT0_EN , intr_en );
58+ spin_unlock_irq (& isp_subdev -> irq_lock );
59+ }
60+
61+ static void isp4_wake_up_resp_thread (struct isp4_subdev * isp_subdev , u32 index )
62+ {
63+ struct isp4sd_thread_handler * thread_ctx =
64+ & isp_subdev -> fw_resp_thread [index ];
65+
66+ thread_ctx -> resp_ready = true;
67+ wake_up_interruptible (& thread_ctx -> waitq );
68+ }
69+
3270static irqreturn_t isp4_irq_handler (int irq , void * arg )
3371{
72+ struct isp4_subdev * isp_subdev = arg ;
73+ u32 intr_ack = 0 , intr_en = 0 , intr_status ;
74+ int seen = 0 ;
75+
76+ /* Get the ISP_SYS interrupt status */
77+ intr_status = isp4hw_rreg (isp_subdev -> mmio , ISP_SYS_INT0_STATUS );
78+ intr_status &= ISP4_FW_RESP_RB_IRQ_STATUS_MASK ;
79+
80+ /* Find which ISP_SYS interrupts fired */
81+ for (size_t i = 0 ; i < ARRAY_SIZE (isp4_irq ); i ++ ) {
82+ if (intr_status & isp4_irq [i ].status_mask ) {
83+ intr_ack |= isp4_irq [i ].ack_mask ;
84+ intr_en |= isp4_irq [i ].en_mask ;
85+ seen |= BIT (i );
86+ }
87+ }
88+
89+ /*
90+ * Disable the ISP_SYS interrupts that fired. Must be done before waking
91+ * the response threads, since they re-enable interrupts when finished.
92+ * The lock synchronizes RMW of INT0_EN with isp4_enable_interrupt().
93+ */
94+ spin_lock (& isp_subdev -> irq_lock );
95+ intr_en = isp4hw_rreg (isp_subdev -> mmio , ISP_SYS_INT0_EN ) & ~intr_en ;
96+ isp4hw_wreg (isp_subdev -> mmio , ISP_SYS_INT0_EN , intr_en );
97+ spin_unlock (& isp_subdev -> irq_lock );
98+
99+ /*
100+ * Clear the ISP_SYS interrupts. This must be done after the interrupts
101+ * are disabled, so that ISP FW won't flag any new interrupts on these
102+ * streams, and thus we don't need to clear interrupts again before
103+ * re-enabling them in the response thread.
104+ */
105+ isp4hw_wreg (isp_subdev -> mmio , ISP_SYS_INT0_ACK , intr_ack );
106+
107+ /*
108+ * The operation `(seen >> i) << i` is logically equivalent to
109+ * `seen &= ~BIT(i)`, with fewer instructions after compilation.
110+ */
111+ for (int i ; (i = ffs (seen )); seen = (seen >> i ) << i )
112+ isp4_wake_up_resp_thread (isp_subdev , i - 1 );
113+
34114 return IRQ_HANDLED ;
35115}
36116
37117static int isp4_capture_probe (struct platform_device * pdev )
38118{
119+ int irq [ISP4SD_MAX_FW_RESP_STREAM_NUM ];
39120 struct device * dev = & pdev -> dev ;
40- int irq [ ARRAY_SIZE ( isp4_irq )] ;
121+ struct isp4_subdev * isp_subdev ;
41122 struct isp4_device * isp_dev ;
42123 int ret ;
43124
@@ -47,6 +128,12 @@ static int isp4_capture_probe(struct platform_device *pdev)
47128
48129 dev -> init_name = ISP4_DRV_NAME ;
49130
131+ isp_subdev = & isp_dev -> isp_subdev ;
132+ isp_subdev -> mmio = devm_platform_ioremap_resource (pdev , 0 );
133+ if (IS_ERR (isp_subdev -> mmio ))
134+ return dev_err_probe (dev , PTR_ERR (isp_subdev -> mmio ),
135+ "isp ioremap fail\n" );
136+
50137 for (size_t i = 0 ; i < ARRAY_SIZE (isp4_irq ); i ++ ) {
51138 irq [i ] = platform_get_irq (pdev , isp4_irq [i ].rb_int_num );
52139 if (irq [i ] < 0 )
@@ -55,7 +142,8 @@ static int isp4_capture_probe(struct platform_device *pdev)
55142 isp4_irq [i ].rb_int_num );
56143
57144 ret = devm_request_irq (dev , irq [i ], isp4_irq_handler ,
58- IRQF_NO_AUTOEN , isp4_irq [i ].name , dev );
145+ IRQF_NO_AUTOEN , isp4_irq [i ].name ,
146+ isp_subdev );
59147 if (ret )
60148 return dev_err_probe (dev , ret , "fail to req irq %d\n" ,
61149 irq [i ]);
@@ -78,6 +166,13 @@ static int isp4_capture_probe(struct platform_device *pdev)
78166
79167 pm_runtime_set_suspended (dev );
80168 pm_runtime_enable (dev );
169+ spin_lock_init (& isp_subdev -> irq_lock );
170+ ret = isp4sd_init (& isp_dev -> isp_subdev , & isp_dev -> v4l2_dev , irq );
171+ if (ret ) {
172+ dev_err_probe (dev , ret , "fail init isp4 sub dev\n" );
173+ goto err_pm_disable ;
174+ }
175+
81176 ret = media_device_register (& isp_dev -> mdev );
82177 if (ret ) {
83178 dev_err_probe (dev , ret , "fail to register media device\n" );
@@ -89,6 +184,8 @@ static int isp4_capture_probe(struct platform_device *pdev)
89184 return 0 ;
90185
91186err_isp4_deinit :
187+ isp4sd_deinit (& isp_dev -> isp_subdev );
188+ err_pm_disable :
92189 pm_runtime_disable (dev );
93190 v4l2_device_unregister (& isp_dev -> v4l2_dev );
94191err_clean_media :
@@ -103,6 +200,7 @@ static void isp4_capture_remove(struct platform_device *pdev)
103200 struct device * dev = & pdev -> dev ;
104201
105202 media_device_unregister (& isp_dev -> mdev );
203+ isp4sd_deinit (& isp_dev -> isp_subdev );
106204 pm_runtime_disable (dev );
107205 v4l2_device_unregister (& isp_dev -> v4l2_dev );
108206 media_device_cleanup (& isp_dev -> mdev );
0 commit comments