1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2025 Advanced Micro Devices, Inc. 4 */ 5 6 #include <linux/irq.h> 7 #include <linux/pm_runtime.h> 8 #include <linux/vmalloc.h> 9 #include <media/v4l2-ioctl.h> 10 11 #include "isp4.h" 12 #include "isp4_debug.h" 13 #include "isp4_hw_reg.h" 14 15 #define ISP4_DRV_NAME "amd_isp_capture" 16 #define ISP4_FW_RESP_RB_IRQ_STATUS_MASK \ 17 (ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK | \ 18 ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK) 19 20 static const struct { 21 const char *name; 22 u32 status_mask; 23 u32 en_mask; 24 u32 ack_mask; 25 u32 rb_int_num; 26 } isp4_irq[ISP4SD_MAX_FW_RESP_STREAM_NUM] = { 27 /* The IRQ order is aligned with the isp4_subdev.fw_resp_thread order */ 28 { 29 .name = "isp_irq_global", 30 .status_mask = 31 ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT12_INT_MASK, 32 .en_mask = ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT12_EN_MASK, 33 .ack_mask = ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT12_ACK_MASK, 34 .rb_int_num = 4, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT12 */ 35 }, 36 { 37 .name = "isp_irq_stream1", 38 .status_mask = 39 ISP_SYS_INT0_STATUS__SYS_INT_RINGBUFFER_WPT9_INT_MASK, 40 .en_mask = ISP_SYS_INT0_EN__SYS_INT_RINGBUFFER_WPT9_EN_MASK, 41 .ack_mask = ISP_SYS_INT0_ACK__SYS_INT_RINGBUFFER_WPT9_ACK_MASK, 42 .rb_int_num = 0, /* ISP_4_1__SRCID__ISP_RINGBUFFER_WPT9 */ 43 }, 44 }; 45 46 void isp4_intr_enable(struct isp4_subdev *isp_subdev, u32 index, bool enable) 47 { 48 u32 intr_en; 49 50 /* Synchronize ISP_SYS_INT0_EN writes with the IRQ handler's writes */ 51 spin_lock_irq(&isp_subdev->irq_lock); 52 intr_en = isp4hw_rreg(isp_subdev->mmio, ISP_SYS_INT0_EN); 53 if (enable) 54 intr_en |= isp4_irq[index].en_mask; 55 else 56 intr_en &= ~isp4_irq[index].en_mask; 57 58 isp4hw_wreg(isp_subdev->mmio, ISP_SYS_INT0_EN, intr_en); 59 spin_unlock_irq(&isp_subdev->irq_lock); 60 } 61 62 static void isp4_wake_up_resp_thread(struct isp4_subdev *isp_subdev, u32 index) 63 { 64 struct isp4sd_thread_handler *thread_ctx = 65 &isp_subdev->fw_resp_thread[index]; 66 67 thread_ctx->resp_ready = true; 68 wake_up_interruptible(&thread_ctx->waitq); 69 } 70 71 static irqreturn_t isp4_irq_handler(int irq, void *arg) 72 { 73 struct isp4_subdev *isp_subdev = arg; 74 u32 intr_ack = 0, intr_en = 0, intr_status; 75 int seen = 0; 76 77 /* Get the ISP_SYS interrupt status */ 78 intr_status = isp4hw_rreg(isp_subdev->mmio, ISP_SYS_INT0_STATUS); 79 intr_status &= ISP4_FW_RESP_RB_IRQ_STATUS_MASK; 80 81 /* Find which ISP_SYS interrupts fired */ 82 for (size_t i = 0; i < ARRAY_SIZE(isp4_irq); i++) { 83 if (intr_status & isp4_irq[i].status_mask) { 84 intr_ack |= isp4_irq[i].ack_mask; 85 intr_en |= isp4_irq[i].en_mask; 86 seen |= BIT(i); 87 } 88 } 89 90 /* 91 * Disable the ISP_SYS interrupts that fired. Must be done before waking 92 * the response threads, since they re-enable interrupts when finished. 93 * The lock synchronizes RMW of INT0_EN with isp4_enable_interrupt(). 94 */ 95 spin_lock(&isp_subdev->irq_lock); 96 intr_en = isp4hw_rreg(isp_subdev->mmio, ISP_SYS_INT0_EN) & ~intr_en; 97 isp4hw_wreg(isp_subdev->mmio, ISP_SYS_INT0_EN, intr_en); 98 spin_unlock(&isp_subdev->irq_lock); 99 100 /* 101 * Clear the ISP_SYS interrupts. This must be done after the interrupts 102 * are disabled, so that ISP FW won't flag any new interrupts on these 103 * streams, and thus we don't need to clear interrupts again before 104 * re-enabling them in the response thread. 105 */ 106 isp4hw_wreg(isp_subdev->mmio, ISP_SYS_INT0_ACK, intr_ack); 107 108 /* 109 * The operation `(seen >> i) << i` is logically equivalent to 110 * `seen &= ~BIT(i)`, with fewer instructions after compilation. 111 */ 112 for (int i; (i = ffs(seen)); seen = (seen >> i) << i) 113 isp4_wake_up_resp_thread(isp_subdev, i - 1); 114 115 return IRQ_HANDLED; 116 } 117 118 static int isp4_capture_probe(struct platform_device *pdev) 119 { 120 int irq[ISP4SD_MAX_FW_RESP_STREAM_NUM]; 121 struct device *dev = &pdev->dev; 122 struct isp4_subdev *isp_subdev; 123 struct isp4_device *isp_dev; 124 int ret; 125 126 isp_dev = devm_kzalloc(dev, sizeof(*isp_dev), GFP_KERNEL); 127 if (!isp_dev) 128 return -ENOMEM; 129 130 dev->init_name = ISP4_DRV_NAME; 131 132 isp_subdev = &isp_dev->isp_subdev; 133 isp_subdev->mmio = devm_platform_ioremap_resource(pdev, 0); 134 if (IS_ERR(isp_subdev->mmio)) 135 return dev_err_probe(dev, PTR_ERR(isp_subdev->mmio), 136 "isp ioremap fail\n"); 137 138 for (size_t i = 0; i < ARRAY_SIZE(isp4_irq); i++) { 139 irq[i] = platform_get_irq(pdev, isp4_irq[i].rb_int_num); 140 if (irq[i] < 0) 141 return dev_err_probe(dev, irq[i], 142 "fail to get irq %d\n", 143 isp4_irq[i].rb_int_num); 144 145 ret = devm_request_irq(dev, irq[i], isp4_irq_handler, 146 IRQF_NO_AUTOEN, isp4_irq[i].name, 147 isp_subdev); 148 if (ret) 149 return dev_err_probe(dev, ret, "fail to req irq %d\n", 150 irq[i]); 151 } 152 153 isp_dev->v4l2_dev.mdev = &isp_dev->mdev; 154 155 strscpy(isp_dev->mdev.model, "amd_isp41_mdev", 156 sizeof(isp_dev->mdev.model)); 157 isp_dev->mdev.dev = dev; 158 media_device_init(&isp_dev->mdev); 159 160 snprintf(isp_dev->v4l2_dev.name, sizeof(isp_dev->v4l2_dev.name), 161 "AMD-V4L2-ROOT"); 162 ret = v4l2_device_register(dev, &isp_dev->v4l2_dev); 163 if (ret) { 164 dev_err_probe(dev, ret, "fail register v4l2 device\n"); 165 goto err_clean_media; 166 } 167 168 pm_runtime_set_suspended(dev); 169 pm_runtime_enable(dev); 170 spin_lock_init(&isp_subdev->irq_lock); 171 ret = isp4sd_init(&isp_dev->isp_subdev, &isp_dev->v4l2_dev, irq); 172 if (ret) { 173 dev_err_probe(dev, ret, "fail init isp4 sub dev\n"); 174 goto err_pm_disable; 175 } 176 177 ret = media_create_pad_link(&isp_dev->isp_subdev.sdev.entity, 178 0, 179 &isp_dev->isp_subdev.isp_vdev.vdev.entity, 180 0, 181 MEDIA_LNK_FL_ENABLED | 182 MEDIA_LNK_FL_IMMUTABLE); 183 if (ret) { 184 dev_err_probe(dev, ret, "fail to create pad link\n"); 185 goto err_isp4_deinit; 186 } 187 188 ret = media_device_register(&isp_dev->mdev); 189 if (ret) { 190 dev_err_probe(dev, ret, "fail to register media device\n"); 191 goto err_isp4_deinit; 192 } 193 194 platform_set_drvdata(pdev, isp_dev); 195 isp_debugfs_create(isp_dev); 196 197 return 0; 198 199 err_isp4_deinit: 200 isp4sd_deinit(&isp_dev->isp_subdev); 201 err_pm_disable: 202 pm_runtime_disable(dev); 203 v4l2_device_unregister(&isp_dev->v4l2_dev); 204 err_clean_media: 205 media_device_cleanup(&isp_dev->mdev); 206 207 return ret; 208 } 209 210 static void isp4_capture_remove(struct platform_device *pdev) 211 { 212 struct isp4_device *isp_dev = platform_get_drvdata(pdev); 213 struct device *dev = &pdev->dev; 214 215 isp_debugfs_remove(isp_dev); 216 217 media_device_unregister(&isp_dev->mdev); 218 isp4sd_deinit(&isp_dev->isp_subdev); 219 pm_runtime_disable(dev); 220 v4l2_device_unregister(&isp_dev->v4l2_dev); 221 media_device_cleanup(&isp_dev->mdev); 222 } 223 224 static struct platform_driver isp4_capture_drv = { 225 .probe = isp4_capture_probe, 226 .remove = isp4_capture_remove, 227 .driver = { 228 .name = ISP4_DRV_NAME, 229 } 230 }; 231 232 module_platform_driver(isp4_capture_drv); 233 234 MODULE_ALIAS("platform:" ISP4_DRV_NAME); 235 MODULE_IMPORT_NS("DMA_BUF"); 236 237 MODULE_DESCRIPTION("AMD ISP4 Driver"); 238 MODULE_AUTHOR("Bin Du <bin.du@amd.com>"); 239 MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>"); 240 MODULE_LICENSE("GPL"); 241