1// SPDX-License-Identifier: GPL-2.0-only OR MIT
2/* Copyright The Asahi Linux Contributors */
3
4#include <drm/drm_modes.h>
5#include <drm/drm_rect.h>
6
7#include "dcp-internal.h"
8
9struct apple_dcp;
10
11typedef void (*dcp_callback_t)(struct apple_dcp *, void *, void *);
12
13
14#define DCP_THUNK_VOID(func, handle)                                         \
15	static void func(struct apple_dcp *dcp, bool oob, dcp_callback_t cb, \
16			 void *cookie)                                       \
17	{                                                                    \
18		dcp_push(dcp, oob, &dcp_methods[handle], 0, 0, NULL, cb, cookie);          \
19	}
20
21#define DCP_THUNK_OUT(func, handle, T)                                       \
22	static void func(struct apple_dcp *dcp, bool oob, dcp_callback_t cb, \
23			 void *cookie)                                       \
24	{                                                                    \
25		dcp_push(dcp, oob, &dcp_methods[handle], 0, sizeof(T), NULL, cb, cookie);  \
26	}
27
28#define DCP_THUNK_IN(func, handle, T)                                       \
29	static void func(struct apple_dcp *dcp, bool oob, T *data,          \
30			 dcp_callback_t cb, void *cookie)                   \
31	{                                                                   \
32		dcp_push(dcp, oob, &dcp_methods[handle], sizeof(T), 0, data, cb, cookie); \
33	}
34
35#define DCP_THUNK_INOUT(func, handle, T_in, T_out)                            \
36	static void func(struct apple_dcp *dcp, bool oob, T_in *data,         \
37			 dcp_callback_t cb, void *cookie)                     \
38	{                                                                     \
39		dcp_push(dcp, oob, &dcp_methods[handle], sizeof(T_in), sizeof(T_out), data, \
40			 cb, cookie);                                         \
41	}
42
43#define IOMFB_THUNK_INOUT(name)                                     \
44	static void iomfb_ ## name(struct apple_dcp *dcp, bool oob, \
45			struct iomfb_ ## name ## _req *data,        \
46			dcp_callback_t cb, void *cookie)            \
47	{                                                           \
48		dcp_push(dcp, oob, &dcp_methods[iomfbep_ ## name],                \
49			 sizeof(struct iomfb_ ## name ## _req),     \
50			 sizeof(struct iomfb_ ## name ## _resp),    \
51			 data,  cb, cookie);                        \
52	}
53
54/*
55 * Define type-safe trampolines. Define typedefs to enforce type-safety on the
56 * input data (so if the types don't match, gcc errors out).
57 */
58
59#define TRAMPOLINE_VOID(func, handler)                                        \
60	static bool __maybe_unused func(struct apple_dcp *dcp, int tag, void *out, void *in) \
61	{                                                                     \
62		trace_iomfb_callback(dcp, tag, #handler);                     \
63		handler(dcp);                                                 \
64		return true;                                                  \
65	}
66
67#define TRAMPOLINE_IN(func, handler, T_in)                                    \
68	typedef void (*callback_##handler)(struct apple_dcp *, T_in *);       \
69                                                                              \
70	static bool __maybe_unused func(struct apple_dcp *dcp, int tag, void *out, void *in) \
71	{                                                                     \
72		callback_##handler cb = handler;                              \
73                                                                              \
74		trace_iomfb_callback(dcp, tag, #handler);                     \
75		cb(dcp, in);                                                  \
76		return true;                                                  \
77	}
78
79#define TRAMPOLINE_INOUT(func, handler, T_in, T_out)                          \
80	typedef T_out (*callback_##handler)(struct apple_dcp *, T_in *);      \
81                                                                              \
82	static bool __maybe_unused func(struct apple_dcp *dcp, int tag, void *out, void *in) \
83	{                                                                     \
84		T_out *typed_out = out;                                       \
85		callback_##handler cb = handler;                              \
86                                                                              \
87		trace_iomfb_callback(dcp, tag, #handler);                     \
88		*typed_out = cb(dcp, in);                                     \
89		return true;                                                  \
90	}
91
92#define TRAMPOLINE_OUT(func, handler, T_out)                                  \
93	static bool __maybe_unused func(struct apple_dcp *dcp, int tag, void *out, void *in) \
94	{                                                                     \
95		T_out *typed_out = out;                                       \
96                                                                              \
97		trace_iomfb_callback(dcp, tag, #handler);                     \
98		*typed_out = handler(dcp);                                    \
99		return true;                                                  \
100	}
101
102/* Call a DCP function given by a tag */
103void dcp_push(struct apple_dcp *dcp, bool oob, const struct dcp_method_entry *call,
104		     u32 in_len, u32 out_len, void *data, dcp_callback_t cb,
105		     void *cookie);
106
107/* Parse a callback tag "D123" into the ID 123. Returns -EINVAL on failure. */
108int dcp_parse_tag(char tag[4]);
109
110void dcp_ack(struct apple_dcp *dcp, enum dcp_context_id context);
111
112/*
113 * DRM specifies rectangles as start and end coordinates.  DCP specifies
114 * rectangles as a start coordinate and a width/height. Convert a DRM rectangle
115 * to a DCP rectangle.
116 */
117struct dcp_rect drm_to_dcp_rect(struct drm_rect *rect);
118
119u32 drm_format_to_dcp(u32 drm);
120
121/* The user may own drm_display_mode, so we need to search for our copy */
122struct dcp_display_mode *lookup_mode(struct apple_dcp *dcp,
123					    const struct drm_display_mode *mode);
124