xref: /linux/drivers/media/platform/amd/isp4/isp4.c (revision d639d9fa162aadec1ae9980c4dcf6e50bd2f8290)
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