Merge tag 'amlogic-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman...
[sfrench/cifs-2.6.git] / drivers / media / platform / mtk-vcodec / mtk_vcodec_fw.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include "mtk_vcodec_fw.h"
4 #include "mtk_vcodec_util.h"
5 #include "mtk_vcodec_drv.h"
6
7 struct mtk_vcodec_fw_ops {
8         int (*load_firmware)(struct mtk_vcodec_fw *fw);
9         unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw);
10         unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw);
11         void * (*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr);
12         int (*ipi_register)(struct mtk_vcodec_fw *fw, int id,
13                             mtk_vcodec_ipi_handler handler, const char *name, void *priv);
14         int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf,
15                         unsigned int len, unsigned int wait);
16 };
17
18 struct mtk_vcodec_fw {
19         enum mtk_vcodec_fw_type type;
20         const struct mtk_vcodec_fw_ops *ops;
21         struct platform_device *pdev;
22         struct mtk_scp *scp;
23 };
24
25 static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw)
26 {
27         return vpu_load_firmware(fw->pdev);
28 }
29
30 static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw)
31 {
32         return vpu_get_vdec_hw_capa(fw->pdev);
33 }
34
35 static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw)
36 {
37         return vpu_get_venc_hw_capa(fw->pdev);
38 }
39
40 static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw,
41                                         u32 dtcm_dmem_addr)
42 {
43         return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr);
44 }
45
46 static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
47                                            mtk_vcodec_ipi_handler handler,
48                                            const char *name, void *priv)
49 {
50         /*
51          * The handler we receive takes a void * as its first argument. We
52          * cannot change this because it needs to be passed down to the rproc
53          * subsystem when SCP is used. VPU takes a const argument, which is
54          * more constrained, so the conversion below is safe.
55          */
56         ipi_handler_t handler_const = (ipi_handler_t)handler;
57
58         return vpu_ipi_register(fw->pdev, id, handler_const, name, priv);
59 }
60
61 static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
62                                    unsigned int len, unsigned int wait)
63 {
64         return vpu_ipi_send(fw->pdev, id, buf, len);
65 }
66
67 static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = {
68         .load_firmware = mtk_vcodec_vpu_load_firmware,
69         .get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa,
70         .get_venc_capa = mtk_vcodec_vpu_get_venc_capa,
71         .map_dm_addr = mtk_vcodec_vpu_map_dm_addr,
72         .ipi_register = mtk_vcodec_vpu_set_ipi_register,
73         .ipi_send = mtk_vcodec_vpu_ipi_send,
74 };
75
76 static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw)
77 {
78         return rproc_boot(scp_get_rproc(fw->scp));
79 }
80
81 static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw)
82 {
83         return scp_get_vdec_hw_capa(fw->scp);
84 }
85
86 static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw)
87 {
88         return scp_get_venc_hw_capa(fw->scp);
89 }
90
91 static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw,
92                                         u32 dtcm_dmem_addr)
93 {
94         return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr);
95 }
96
97 static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
98                                            mtk_vcodec_ipi_handler handler,
99                                            const char *name, void *priv)
100 {
101         return scp_ipi_register(fw->scp, id, handler, priv);
102 }
103
104 static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
105                                    unsigned int len, unsigned int wait)
106 {
107         return scp_ipi_send(fw->scp, id, buf, len, wait);
108 }
109
110 static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = {
111         .load_firmware = mtk_vcodec_scp_load_firmware,
112         .get_vdec_capa = mtk_vcodec_scp_get_vdec_capa,
113         .get_venc_capa = mtk_vcodec_scp_get_venc_capa,
114         .map_dm_addr = mtk_vcodec_vpu_scp_dm_addr,
115         .ipi_register = mtk_vcodec_scp_set_ipi_register,
116         .ipi_send = mtk_vcodec_scp_ipi_send,
117 };
118
119 static void mtk_vcodec_reset_handler(void *priv)
120 {
121         struct mtk_vcodec_dev *dev = priv;
122         struct mtk_vcodec_ctx *ctx;
123
124         mtk_v4l2_err("Watchdog timeout!!");
125
126         mutex_lock(&dev->dev_mutex);
127         list_for_each_entry(ctx, &dev->ctx_list, list) {
128                 ctx->state = MTK_STATE_ABORT;
129                 mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT",
130                                ctx->id);
131         }
132         mutex_unlock(&dev->dev_mutex);
133 }
134
135 struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev,
136                                            enum mtk_vcodec_fw_type type,
137                                            enum rst_id rst_id)
138 {
139         const struct mtk_vcodec_fw_ops *ops;
140         struct mtk_vcodec_fw *fw;
141         struct platform_device *fw_pdev = NULL;
142         struct mtk_scp *scp = NULL;
143
144         switch (type) {
145         case VPU:
146                 ops = &mtk_vcodec_vpu_msg;
147                 fw_pdev = vpu_get_plat_device(dev->plat_dev);
148                 if (!fw_pdev) {
149                         mtk_v4l2_err("firmware device is not ready");
150                         return ERR_PTR(-EINVAL);
151                 }
152                 vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_reset_handler,
153                                     dev, rst_id);
154                 break;
155         case SCP:
156                 ops = &mtk_vcodec_rproc_msg;
157                 scp = scp_get(dev->plat_dev);
158                 if (!scp) {
159                         mtk_v4l2_err("could not get vdec scp handle");
160                         return ERR_PTR(-EPROBE_DEFER);
161                 }
162                 break;
163         default:
164                 mtk_v4l2_err("invalid vcodec fw type");
165                 return ERR_PTR(-EINVAL);
166         }
167
168         fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL);
169         if (!fw)
170                 return ERR_PTR(-EINVAL);
171
172         fw->type = type;
173         fw->ops = ops;
174         fw->pdev = fw_pdev;
175         fw->scp = scp;
176
177         return fw;
178 }
179 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_select);
180
181 void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw)
182 {
183         switch (fw->type) {
184         case VPU:
185                 put_device(&fw->pdev->dev);
186                 break;
187         case SCP:
188                 scp_put(fw->scp);
189                 break;
190         }
191 }
192 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_release);
193
194 int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw)
195 {
196         return fw->ops->load_firmware(fw);
197 }
198 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_load_firmware);
199
200 unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw)
201 {
202         return fw->ops->get_vdec_capa(fw);
203 }
204 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_vdec_capa);
205
206 unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw)
207 {
208         return fw->ops->get_venc_capa(fw);
209 }
210 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_venc_capa);
211
212 void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr)
213 {
214         return fw->ops->map_dm_addr(fw, mem_addr);
215 }
216 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_map_dm_addr);
217
218 int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
219                                mtk_vcodec_ipi_handler handler,
220                                const char *name, void *priv)
221 {
222         return fw->ops->ipi_register(fw, id, handler, name, priv);
223 }
224 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_register);
225
226 int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
227                            unsigned int len, unsigned int wait)
228 {
229         return fw->ops->ipi_send(fw, id, buf, len, wait);
230 }
231 EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send);