xref: /openbsd/sys/dev/pci/drm/apple/dptxep.c (revision 5dd0baa8)
1*5dd0baa8Skettenis // SPDX-License-Identifier: GPL-2.0-only OR MIT
2*5dd0baa8Skettenis /* Copyright 2022 Sven Peter <sven@svenpeter.dev> */
3*5dd0baa8Skettenis 
4*5dd0baa8Skettenis #include <linux/bitfield.h>
5*5dd0baa8Skettenis #include <linux/completion.h>
6*5dd0baa8Skettenis #include <linux/phy/phy.h>
7*5dd0baa8Skettenis #include <linux/delay.h>
8*5dd0baa8Skettenis 
9*5dd0baa8Skettenis #include "afk.h"
10*5dd0baa8Skettenis #include "dcp.h"
11*5dd0baa8Skettenis #include "dptxep.h"
12*5dd0baa8Skettenis #include "parser.h"
13*5dd0baa8Skettenis #include "trace.h"
14*5dd0baa8Skettenis 
15*5dd0baa8Skettenis struct dcpdptx_connection_cmd {
16*5dd0baa8Skettenis 	__le32 unk;
17*5dd0baa8Skettenis 	__le32 target;
18*5dd0baa8Skettenis } __attribute__((packed));
19*5dd0baa8Skettenis 
20*5dd0baa8Skettenis struct dcpdptx_hotplug_cmd {
21*5dd0baa8Skettenis 	u8 _pad0[16];
22*5dd0baa8Skettenis 	__le32 unk;
23*5dd0baa8Skettenis } __attribute__((packed));
24*5dd0baa8Skettenis 
25*5dd0baa8Skettenis struct dptxport_apcall_link_rate {
26*5dd0baa8Skettenis 	__le32 retcode;
27*5dd0baa8Skettenis 	u8 _unk0[12];
28*5dd0baa8Skettenis 	__le32 link_rate;
29*5dd0baa8Skettenis 	u8 _unk1[12];
30*5dd0baa8Skettenis } __attribute__((packed));
31*5dd0baa8Skettenis 
32*5dd0baa8Skettenis struct dptxport_apcall_lane_count {
33*5dd0baa8Skettenis 	__le32 retcode;
34*5dd0baa8Skettenis 	u8 _unk0[12];
35*5dd0baa8Skettenis 	__le64 lane_count;
36*5dd0baa8Skettenis 	u8 _unk1[8];
37*5dd0baa8Skettenis } __attribute__((packed));
38*5dd0baa8Skettenis 
39*5dd0baa8Skettenis struct dptxport_apcall_set_active_lane_count {
40*5dd0baa8Skettenis 	__le32 retcode;
41*5dd0baa8Skettenis 	u8 _unk0[12];
42*5dd0baa8Skettenis 	__le64 lane_count;
43*5dd0baa8Skettenis 	u8 _unk1[8];
44*5dd0baa8Skettenis } __packed;
45*5dd0baa8Skettenis 
46*5dd0baa8Skettenis struct dptxport_apcall_get_support {
47*5dd0baa8Skettenis 	__le32 retcode;
48*5dd0baa8Skettenis 	u8 _unk0[12];
49*5dd0baa8Skettenis 	__le32 supported;
50*5dd0baa8Skettenis 	u8 _unk1[12];
51*5dd0baa8Skettenis } __attribute__((packed));
52*5dd0baa8Skettenis 
53*5dd0baa8Skettenis struct dptxport_apcall_max_drive_settings {
54*5dd0baa8Skettenis 	__le32 retcode;
55*5dd0baa8Skettenis 	u8 _unk0[12];
56*5dd0baa8Skettenis 	__le32 max_drive_settings[2];
57*5dd0baa8Skettenis 	u8 _unk1[8];
58*5dd0baa8Skettenis };
59*5dd0baa8Skettenis 
60*5dd0baa8Skettenis struct dptxport_apcall_drive_settings {
61*5dd0baa8Skettenis 	__le32 retcode;
62*5dd0baa8Skettenis 	u8 _unk0[12];
63*5dd0baa8Skettenis 	__le32 unk1;
64*5dd0baa8Skettenis 	__le32 unk2;
65*5dd0baa8Skettenis 	__le32 unk3;
66*5dd0baa8Skettenis 	__le32 unk4;
67*5dd0baa8Skettenis 	__le32 unk5;
68*5dd0baa8Skettenis 	__le32 unk6;
69*5dd0baa8Skettenis 	__le32 unk7;
70*5dd0baa8Skettenis };
71*5dd0baa8Skettenis 
dptxport_validate_connection(struct apple_epic_service * service,u8 core,u8 atc,u8 die)72*5dd0baa8Skettenis int dptxport_validate_connection(struct apple_epic_service *service, u8 core,
73*5dd0baa8Skettenis 				 u8 atc, u8 die)
74*5dd0baa8Skettenis {
75*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
76*5dd0baa8Skettenis 	struct dcpdptx_connection_cmd cmd, resp;
77*5dd0baa8Skettenis 	int ret;
78*5dd0baa8Skettenis 	u32 target = FIELD_PREP(DCPDPTX_REMOTE_PORT_CORE, core) |
79*5dd0baa8Skettenis 		     FIELD_PREP(DCPDPTX_REMOTE_PORT_ATC, atc) |
80*5dd0baa8Skettenis 		     FIELD_PREP(DCPDPTX_REMOTE_PORT_DIE, die) |
81*5dd0baa8Skettenis 		     DCPDPTX_REMOTE_PORT_CONNECTED;
82*5dd0baa8Skettenis 
83*5dd0baa8Skettenis 	trace_dptxport_validate_connection(dptx, core, atc, die);
84*5dd0baa8Skettenis 
85*5dd0baa8Skettenis 	cmd.target = cpu_to_le32(target);
86*5dd0baa8Skettenis 	cmd.unk = cpu_to_le32(0x100);
87*5dd0baa8Skettenis 	ret = afk_service_call(service, 0, 12, &cmd, sizeof(cmd), 40, &resp,
88*5dd0baa8Skettenis 			       sizeof(resp), 40);
89*5dd0baa8Skettenis 	if (ret)
90*5dd0baa8Skettenis 		return ret;
91*5dd0baa8Skettenis 
92*5dd0baa8Skettenis 	if (le32_to_cpu(resp.target) != target)
93*5dd0baa8Skettenis 		return -EINVAL;
94*5dd0baa8Skettenis 	if (le32_to_cpu(resp.unk) != 0x100)
95*5dd0baa8Skettenis 		return -EINVAL;
96*5dd0baa8Skettenis 
97*5dd0baa8Skettenis 	return 0;
98*5dd0baa8Skettenis }
99*5dd0baa8Skettenis 
dptxport_connect(struct apple_epic_service * service,u8 core,u8 atc,u8 die)100*5dd0baa8Skettenis int dptxport_connect(struct apple_epic_service *service, u8 core, u8 atc,
101*5dd0baa8Skettenis 		     u8 die)
102*5dd0baa8Skettenis {
103*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
104*5dd0baa8Skettenis 	struct dcpdptx_connection_cmd cmd, resp;
105*5dd0baa8Skettenis 	u32 unk_field = 0x0; // seen as 0x100 under some conditions
106*5dd0baa8Skettenis 	int ret;
107*5dd0baa8Skettenis 	u32 target = FIELD_PREP(DCPDPTX_REMOTE_PORT_CORE, core) |
108*5dd0baa8Skettenis 		     FIELD_PREP(DCPDPTX_REMOTE_PORT_ATC, atc) |
109*5dd0baa8Skettenis 		     FIELD_PREP(DCPDPTX_REMOTE_PORT_DIE, die) |
110*5dd0baa8Skettenis 		     DCPDPTX_REMOTE_PORT_CONNECTED;
111*5dd0baa8Skettenis 
112*5dd0baa8Skettenis 	trace_dptxport_connect(dptx, core, atc, die);
113*5dd0baa8Skettenis 
114*5dd0baa8Skettenis 	cmd.target = cpu_to_le32(target);
115*5dd0baa8Skettenis 	cmd.unk = cpu_to_le32(unk_field);
116*5dd0baa8Skettenis 	ret = afk_service_call(service, 0, 11, &cmd, sizeof(cmd), 24, &resp,
117*5dd0baa8Skettenis 			       sizeof(resp), 24);
118*5dd0baa8Skettenis 	if (ret)
119*5dd0baa8Skettenis 		return ret;
120*5dd0baa8Skettenis 
121*5dd0baa8Skettenis 	if (le32_to_cpu(resp.target) != target)
122*5dd0baa8Skettenis 		return -EINVAL;
123*5dd0baa8Skettenis 	if (le32_to_cpu(resp.unk) != unk_field)
124*5dd0baa8Skettenis 		dev_notice(service->ep->dcp->dev, "unexpected unk field in reply: 0x%x (0x%x)\n",
125*5dd0baa8Skettenis 			  le32_to_cpu(resp.unk), unk_field);
126*5dd0baa8Skettenis 
127*5dd0baa8Skettenis 	return 0;
128*5dd0baa8Skettenis }
129*5dd0baa8Skettenis 
dptxport_request_display(struct apple_epic_service * service)130*5dd0baa8Skettenis int dptxport_request_display(struct apple_epic_service *service)
131*5dd0baa8Skettenis {
132*5dd0baa8Skettenis 	return afk_service_call(service, 0, 6, NULL, 0, 16, NULL, 0, 16);
133*5dd0baa8Skettenis }
134*5dd0baa8Skettenis 
dptxport_release_display(struct apple_epic_service * service)135*5dd0baa8Skettenis int dptxport_release_display(struct apple_epic_service *service)
136*5dd0baa8Skettenis {
137*5dd0baa8Skettenis 	return afk_service_call(service, 0, 7, NULL, 0, 16, NULL, 0, 16);
138*5dd0baa8Skettenis }
139*5dd0baa8Skettenis 
dptxport_set_hpd(struct apple_epic_service * service,bool hpd)140*5dd0baa8Skettenis int dptxport_set_hpd(struct apple_epic_service *service, bool hpd)
141*5dd0baa8Skettenis {
142*5dd0baa8Skettenis 	struct dcpdptx_hotplug_cmd cmd, resp;
143*5dd0baa8Skettenis 	int ret;
144*5dd0baa8Skettenis 
145*5dd0baa8Skettenis 	memset(&cmd, 0, sizeof(cmd));
146*5dd0baa8Skettenis 
147*5dd0baa8Skettenis 	if (hpd)
148*5dd0baa8Skettenis 		cmd.unk = cpu_to_le32(1);
149*5dd0baa8Skettenis 
150*5dd0baa8Skettenis 	ret = afk_service_call(service, 8, 8, &cmd, sizeof(cmd), 12, &resp,
151*5dd0baa8Skettenis 			       sizeof(resp), 12);
152*5dd0baa8Skettenis 	if (ret)
153*5dd0baa8Skettenis 		return ret;
154*5dd0baa8Skettenis 	if (le32_to_cpu(resp.unk) != 1)
155*5dd0baa8Skettenis 		return -EINVAL;
156*5dd0baa8Skettenis 	return 0;
157*5dd0baa8Skettenis }
158*5dd0baa8Skettenis 
159*5dd0baa8Skettenis static int
dptxport_call_get_max_drive_settings(struct apple_epic_service * service,void * reply_,size_t reply_size)160*5dd0baa8Skettenis dptxport_call_get_max_drive_settings(struct apple_epic_service *service,
161*5dd0baa8Skettenis 				     void *reply_, size_t reply_size)
162*5dd0baa8Skettenis {
163*5dd0baa8Skettenis 	struct dptxport_apcall_max_drive_settings *reply = reply_;
164*5dd0baa8Skettenis 
165*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
166*5dd0baa8Skettenis 		return -EINVAL;
167*5dd0baa8Skettenis 
168*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
169*5dd0baa8Skettenis 	reply->max_drive_settings[0] = cpu_to_le32(0x3);
170*5dd0baa8Skettenis 	reply->max_drive_settings[1] = cpu_to_le32(0x3);
171*5dd0baa8Skettenis 
172*5dd0baa8Skettenis 	return 0;
173*5dd0baa8Skettenis }
174*5dd0baa8Skettenis 
175*5dd0baa8Skettenis static int
dptxport_call_get_drive_settings(struct apple_epic_service * service,const void * request_,size_t request_size,void * reply_,size_t reply_size)176*5dd0baa8Skettenis dptxport_call_get_drive_settings(struct apple_epic_service *service,
177*5dd0baa8Skettenis 				     const void *request_, size_t request_size,
178*5dd0baa8Skettenis 				     void *reply_, size_t reply_size)
179*5dd0baa8Skettenis {
180*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
181*5dd0baa8Skettenis 	const struct dptxport_apcall_drive_settings *request = request_;
182*5dd0baa8Skettenis 	struct dptxport_apcall_drive_settings *reply = reply_;
183*5dd0baa8Skettenis 
184*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply) || request_size < sizeof(*request))
185*5dd0baa8Skettenis 		return -EINVAL;
186*5dd0baa8Skettenis 
187*5dd0baa8Skettenis 	*reply = *request;
188*5dd0baa8Skettenis 
189*5dd0baa8Skettenis 	/* Clear the rest of the buffer */
190*5dd0baa8Skettenis 	memset(reply_ + sizeof(*reply), 0, reply_size - sizeof(*reply));
191*5dd0baa8Skettenis 
192*5dd0baa8Skettenis 	if (reply->retcode != 4)
193*5dd0baa8Skettenis 		dev_err(service->ep->dcp->dev,
194*5dd0baa8Skettenis 			"get_drive_settings: unexpected retcode %d\n",
195*5dd0baa8Skettenis 			reply->retcode);
196*5dd0baa8Skettenis 
197*5dd0baa8Skettenis 	reply->retcode = 4; /* Should already be 4? */
198*5dd0baa8Skettenis 	reply->unk5 = dptx->drive_settings[0];
199*5dd0baa8Skettenis 	reply->unk6 = 0;
200*5dd0baa8Skettenis 	reply->unk7 = dptx->drive_settings[1];
201*5dd0baa8Skettenis 
202*5dd0baa8Skettenis 	return 0;
203*5dd0baa8Skettenis }
204*5dd0baa8Skettenis 
205*5dd0baa8Skettenis static int
dptxport_call_set_drive_settings(struct apple_epic_service * service,const void * request_,size_t request_size,void * reply_,size_t reply_size)206*5dd0baa8Skettenis dptxport_call_set_drive_settings(struct apple_epic_service *service,
207*5dd0baa8Skettenis 				     const void *request_, size_t request_size,
208*5dd0baa8Skettenis 				     void *reply_, size_t reply_size)
209*5dd0baa8Skettenis {
210*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
211*5dd0baa8Skettenis 	const struct dptxport_apcall_drive_settings *request = request_;
212*5dd0baa8Skettenis 	struct dptxport_apcall_drive_settings *reply = reply_;
213*5dd0baa8Skettenis 
214*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply) || request_size < sizeof(*request))
215*5dd0baa8Skettenis 		return -EINVAL;
216*5dd0baa8Skettenis 
217*5dd0baa8Skettenis 	*reply = *request;
218*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
219*5dd0baa8Skettenis 
220*5dd0baa8Skettenis 	dev_info(service->ep->dcp->dev, "set_drive_settings: %d:%d:%d:%d:%d:%d:%d\n",
221*5dd0baa8Skettenis 		 request->unk1, request->unk2, request->unk3, request->unk4,
222*5dd0baa8Skettenis 		 request->unk5, request->unk6, request->unk7);
223*5dd0baa8Skettenis 
224*5dd0baa8Skettenis 	dptx->drive_settings[0] = reply->unk5;
225*5dd0baa8Skettenis 	dptx->drive_settings[1] = reply->unk7;
226*5dd0baa8Skettenis 
227*5dd0baa8Skettenis 	return 0;
228*5dd0baa8Skettenis }
229*5dd0baa8Skettenis 
dptxport_call_get_max_link_rate(struct apple_epic_service * service,void * reply_,size_t reply_size)230*5dd0baa8Skettenis static int dptxport_call_get_max_link_rate(struct apple_epic_service *service,
231*5dd0baa8Skettenis 					   void *reply_, size_t reply_size)
232*5dd0baa8Skettenis {
233*5dd0baa8Skettenis 	struct dptxport_apcall_link_rate *reply = reply_;
234*5dd0baa8Skettenis 
235*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
236*5dd0baa8Skettenis 		return -EINVAL;
237*5dd0baa8Skettenis 
238*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
239*5dd0baa8Skettenis 	reply->link_rate = cpu_to_le32(LINK_RATE_HBR3);
240*5dd0baa8Skettenis 
241*5dd0baa8Skettenis 	return 0;
242*5dd0baa8Skettenis }
243*5dd0baa8Skettenis 
dptxport_call_get_max_lane_count(struct apple_epic_service * service,void * reply_,size_t reply_size)244*5dd0baa8Skettenis static int dptxport_call_get_max_lane_count(struct apple_epic_service *service,
245*5dd0baa8Skettenis 					   void *reply_, size_t reply_size)
246*5dd0baa8Skettenis {
247*5dd0baa8Skettenis 	struct dptxport_apcall_lane_count *reply = reply_;
248*5dd0baa8Skettenis 
249*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
250*5dd0baa8Skettenis 		return -EINVAL;
251*5dd0baa8Skettenis 
252*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
253*5dd0baa8Skettenis 	reply->lane_count = cpu_to_le64(4);
254*5dd0baa8Skettenis 
255*5dd0baa8Skettenis 	return 0;
256*5dd0baa8Skettenis }
257*5dd0baa8Skettenis 
dptxport_call_set_active_lane_count(struct apple_epic_service * service,const void * data,size_t data_size,void * reply_,size_t reply_size)258*5dd0baa8Skettenis static int dptxport_call_set_active_lane_count(struct apple_epic_service *service,
259*5dd0baa8Skettenis 					       const void *data, size_t data_size,
260*5dd0baa8Skettenis 					       void *reply_, size_t reply_size)
261*5dd0baa8Skettenis {
262*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
263*5dd0baa8Skettenis 	const struct dptxport_apcall_set_active_lane_count *request = data;
264*5dd0baa8Skettenis 	struct dptxport_apcall_set_active_lane_count *reply = reply_;
265*5dd0baa8Skettenis 	int ret = 0;
266*5dd0baa8Skettenis 	int retcode = 0;
267*5dd0baa8Skettenis 
268*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
269*5dd0baa8Skettenis 		return -1;
270*5dd0baa8Skettenis 	if (data_size < sizeof(*request))
271*5dd0baa8Skettenis 		return -1;
272*5dd0baa8Skettenis 
273*5dd0baa8Skettenis 	u64 lane_count = cpu_to_le64(request->lane_count);
274*5dd0baa8Skettenis 
275*5dd0baa8Skettenis 	switch (lane_count) {
276*5dd0baa8Skettenis 	case 0 ... 2:
277*5dd0baa8Skettenis 	case 4:
278*5dd0baa8Skettenis 		dptx->phy_ops.dp.lanes = lane_count;
279*5dd0baa8Skettenis 		dptx->phy_ops.dp.set_lanes = 1;
280*5dd0baa8Skettenis 		break;
281*5dd0baa8Skettenis 	default:
282*5dd0baa8Skettenis 		dev_err(service->ep->dcp->dev, "set_active_lane_count: invalid lane count:%llu\n", lane_count);
283*5dd0baa8Skettenis 		retcode = 1;
284*5dd0baa8Skettenis 		lane_count = 0;
285*5dd0baa8Skettenis 		break;
286*5dd0baa8Skettenis 	}
287*5dd0baa8Skettenis 
288*5dd0baa8Skettenis 	if (dptx->phy_ops.dp.set_lanes) {
289*5dd0baa8Skettenis 		if (dptx->atcphy) {
290*5dd0baa8Skettenis 			ret = phy_configure(dptx->atcphy, &dptx->phy_ops);
291*5dd0baa8Skettenis 			if (ret)
292*5dd0baa8Skettenis 				return ret;
293*5dd0baa8Skettenis 		}
294*5dd0baa8Skettenis 		dptx->phy_ops.dp.set_lanes = 0;
295*5dd0baa8Skettenis 	}
296*5dd0baa8Skettenis 
297*5dd0baa8Skettenis 	dptx->lane_count = lane_count;
298*5dd0baa8Skettenis 
299*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(retcode);
300*5dd0baa8Skettenis 	reply->lane_count = cpu_to_le64(lane_count);
301*5dd0baa8Skettenis 
302*5dd0baa8Skettenis 	if (dptx->lane_count > 0)
303*5dd0baa8Skettenis 		complete(&dptx->linkcfg_completion);
304*5dd0baa8Skettenis 
305*5dd0baa8Skettenis 	return ret;
306*5dd0baa8Skettenis }
307*5dd0baa8Skettenis 
dptxport_call_get_link_rate(struct apple_epic_service * service,void * reply_,size_t reply_size)308*5dd0baa8Skettenis static int dptxport_call_get_link_rate(struct apple_epic_service *service,
309*5dd0baa8Skettenis 				       void *reply_, size_t reply_size)
310*5dd0baa8Skettenis {
311*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
312*5dd0baa8Skettenis 	struct dptxport_apcall_link_rate *reply = reply_;
313*5dd0baa8Skettenis 
314*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
315*5dd0baa8Skettenis 		return -EINVAL;
316*5dd0baa8Skettenis 
317*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
318*5dd0baa8Skettenis 	reply->link_rate = cpu_to_le32(dptx->link_rate);
319*5dd0baa8Skettenis 
320*5dd0baa8Skettenis 	return 0;
321*5dd0baa8Skettenis }
322*5dd0baa8Skettenis 
323*5dd0baa8Skettenis static int
dptxport_call_will_change_link_config(struct apple_epic_service * service)324*5dd0baa8Skettenis dptxport_call_will_change_link_config(struct apple_epic_service *service)
325*5dd0baa8Skettenis {
326*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
327*5dd0baa8Skettenis 
328*5dd0baa8Skettenis 	dptx->phy_ops.dp.set_lanes = 0;
329*5dd0baa8Skettenis 	dptx->phy_ops.dp.set_rate = 0;
330*5dd0baa8Skettenis 	dptx->phy_ops.dp.set_voltages = 0;
331*5dd0baa8Skettenis 
332*5dd0baa8Skettenis 	return 0;
333*5dd0baa8Skettenis }
334*5dd0baa8Skettenis 
335*5dd0baa8Skettenis static int
dptxport_call_did_change_link_config(struct apple_epic_service * service)336*5dd0baa8Skettenis dptxport_call_did_change_link_config(struct apple_epic_service *service)
337*5dd0baa8Skettenis {
338*5dd0baa8Skettenis 	/* assume the link config did change and wait a little bit */
339*5dd0baa8Skettenis 	mdelay(10);
340*5dd0baa8Skettenis 
341*5dd0baa8Skettenis 	return 0;
342*5dd0baa8Skettenis }
343*5dd0baa8Skettenis 
dptxport_call_set_link_rate(struct apple_epic_service * service,const void * data,size_t data_size,void * reply_,size_t reply_size)344*5dd0baa8Skettenis static int dptxport_call_set_link_rate(struct apple_epic_service *service,
345*5dd0baa8Skettenis 				       const void *data, size_t data_size,
346*5dd0baa8Skettenis 				       void *reply_, size_t reply_size)
347*5dd0baa8Skettenis {
348*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
349*5dd0baa8Skettenis 	const struct dptxport_apcall_link_rate *request = data;
350*5dd0baa8Skettenis 	struct dptxport_apcall_link_rate *reply = reply_;
351*5dd0baa8Skettenis 	u32 link_rate, phy_link_rate;
352*5dd0baa8Skettenis 	bool phy_set_rate = false;
353*5dd0baa8Skettenis 	int ret;
354*5dd0baa8Skettenis 
355*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
356*5dd0baa8Skettenis 		return -EINVAL;
357*5dd0baa8Skettenis 	if (data_size < sizeof(*request))
358*5dd0baa8Skettenis 		return -EINVAL;
359*5dd0baa8Skettenis 
360*5dd0baa8Skettenis 	link_rate = le32_to_cpu(request->link_rate);
361*5dd0baa8Skettenis 	trace_dptxport_call_set_link_rate(dptx, link_rate);
362*5dd0baa8Skettenis 
363*5dd0baa8Skettenis 	switch (link_rate) {
364*5dd0baa8Skettenis 	case LINK_RATE_RBR:
365*5dd0baa8Skettenis 		phy_link_rate = 1620;
366*5dd0baa8Skettenis 		phy_set_rate = true;
367*5dd0baa8Skettenis 		break;
368*5dd0baa8Skettenis 	case LINK_RATE_HBR:
369*5dd0baa8Skettenis 		phy_link_rate = 2700;
370*5dd0baa8Skettenis 		phy_set_rate = true;
371*5dd0baa8Skettenis 		break;
372*5dd0baa8Skettenis 	case LINK_RATE_HBR2:
373*5dd0baa8Skettenis 		phy_link_rate = 5400;
374*5dd0baa8Skettenis 		phy_set_rate = true;
375*5dd0baa8Skettenis 		break;
376*5dd0baa8Skettenis 	case LINK_RATE_HBR3:
377*5dd0baa8Skettenis 		phy_link_rate = 8100;
378*5dd0baa8Skettenis 		phy_set_rate = true;
379*5dd0baa8Skettenis 		break;
380*5dd0baa8Skettenis 	case 0:
381*5dd0baa8Skettenis 		phy_link_rate = 0;
382*5dd0baa8Skettenis 		phy_set_rate = true;
383*5dd0baa8Skettenis 		break;
384*5dd0baa8Skettenis 	default:
385*5dd0baa8Skettenis 		dev_err(service->ep->dcp->dev,
386*5dd0baa8Skettenis 			"DPTXPort: Unsupported link rate 0x%x requested\n",
387*5dd0baa8Skettenis 			link_rate);
388*5dd0baa8Skettenis 		link_rate = 0;
389*5dd0baa8Skettenis 		phy_set_rate = false;
390*5dd0baa8Skettenis 		break;
391*5dd0baa8Skettenis 	}
392*5dd0baa8Skettenis 
393*5dd0baa8Skettenis 	if (phy_set_rate) {
394*5dd0baa8Skettenis 		dptx->phy_ops.dp.link_rate = phy_link_rate;
395*5dd0baa8Skettenis 		dptx->phy_ops.dp.set_rate = 1;
396*5dd0baa8Skettenis 
397*5dd0baa8Skettenis 		if (dptx->atcphy) {
398*5dd0baa8Skettenis 			ret = phy_configure(dptx->atcphy, &dptx->phy_ops);
399*5dd0baa8Skettenis 			if (ret)
400*5dd0baa8Skettenis 				return ret;
401*5dd0baa8Skettenis 		}
402*5dd0baa8Skettenis 
403*5dd0baa8Skettenis 		//if (dptx->phy_ops.dp.set_rate)
404*5dd0baa8Skettenis 		dptx->link_rate = dptx->pending_link_rate = link_rate;
405*5dd0baa8Skettenis 
406*5dd0baa8Skettenis 	}
407*5dd0baa8Skettenis 
408*5dd0baa8Skettenis 	//dptx->pending_link_rate = link_rate;
409*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
410*5dd0baa8Skettenis 	reply->link_rate = cpu_to_le32(link_rate);
411*5dd0baa8Skettenis 
412*5dd0baa8Skettenis 	return 0;
413*5dd0baa8Skettenis }
414*5dd0baa8Skettenis 
dptxport_call_get_supports_hpd(struct apple_epic_service * service,void * reply_,size_t reply_size)415*5dd0baa8Skettenis static int dptxport_call_get_supports_hpd(struct apple_epic_service *service,
416*5dd0baa8Skettenis 					  void *reply_, size_t reply_size)
417*5dd0baa8Skettenis {
418*5dd0baa8Skettenis 	struct dptxport_apcall_get_support *reply = reply_;
419*5dd0baa8Skettenis 
420*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
421*5dd0baa8Skettenis 		return -EINVAL;
422*5dd0baa8Skettenis 
423*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
424*5dd0baa8Skettenis 	reply->supported = cpu_to_le32(0);
425*5dd0baa8Skettenis 	return 0;
426*5dd0baa8Skettenis }
427*5dd0baa8Skettenis 
428*5dd0baa8Skettenis static int
dptxport_call_get_supports_downspread(struct apple_epic_service * service,void * reply_,size_t reply_size)429*5dd0baa8Skettenis dptxport_call_get_supports_downspread(struct apple_epic_service *service,
430*5dd0baa8Skettenis 				      void *reply_, size_t reply_size)
431*5dd0baa8Skettenis {
432*5dd0baa8Skettenis 	struct dptxport_apcall_get_support *reply = reply_;
433*5dd0baa8Skettenis 
434*5dd0baa8Skettenis 	if (reply_size < sizeof(*reply))
435*5dd0baa8Skettenis 		return -EINVAL;
436*5dd0baa8Skettenis 
437*5dd0baa8Skettenis 	reply->retcode = cpu_to_le32(0);
438*5dd0baa8Skettenis 	reply->supported = cpu_to_le32(0);
439*5dd0baa8Skettenis 	return 0;
440*5dd0baa8Skettenis }
441*5dd0baa8Skettenis 
442*5dd0baa8Skettenis static int
dptxport_call_activate(struct apple_epic_service * service,const void * data,size_t data_size,void * reply,size_t reply_size)443*5dd0baa8Skettenis dptxport_call_activate(struct apple_epic_service *service,
444*5dd0baa8Skettenis 		       const void *data, size_t data_size,
445*5dd0baa8Skettenis 		       void *reply, size_t reply_size)
446*5dd0baa8Skettenis {
447*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
448*5dd0baa8Skettenis 	const struct apple_dcp *dcp = service->ep->dcp;
449*5dd0baa8Skettenis 
450*5dd0baa8Skettenis 	// TODO: hack, use phy_set_mode to select the correct DCP(EXT) input
451*5dd0baa8Skettenis 	phy_set_mode_ext(dptx->atcphy, PHY_MODE_DP, dcp->index);
452*5dd0baa8Skettenis 
453*5dd0baa8Skettenis 	memcpy(reply, data, min(reply_size, data_size));
454*5dd0baa8Skettenis 	if (reply_size >= 4)
455*5dd0baa8Skettenis 		memset(reply, 0, 4);
456*5dd0baa8Skettenis 
457*5dd0baa8Skettenis 	return 0;
458*5dd0baa8Skettenis }
459*5dd0baa8Skettenis 
460*5dd0baa8Skettenis static int
dptxport_call_deactivate(struct apple_epic_service * service,const void * data,size_t data_size,void * reply,size_t reply_size)461*5dd0baa8Skettenis dptxport_call_deactivate(struct apple_epic_service *service,
462*5dd0baa8Skettenis 		       const void *data, size_t data_size,
463*5dd0baa8Skettenis 		       void *reply, size_t reply_size)
464*5dd0baa8Skettenis {
465*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
466*5dd0baa8Skettenis 
467*5dd0baa8Skettenis 	/* deactivate phy */
468*5dd0baa8Skettenis 	phy_set_mode_ext(dptx->atcphy, PHY_MODE_INVALID, 0);
469*5dd0baa8Skettenis 
470*5dd0baa8Skettenis 	memcpy(reply, data, min(reply_size, data_size));
471*5dd0baa8Skettenis 	if (reply_size >= 4)
472*5dd0baa8Skettenis 		memset(reply, 0, 4);
473*5dd0baa8Skettenis 
474*5dd0baa8Skettenis 	return 0;
475*5dd0baa8Skettenis }
476*5dd0baa8Skettenis 
dptxport_call(struct apple_epic_service * service,u32 idx,const void * data,size_t data_size,void * reply,size_t reply_size)477*5dd0baa8Skettenis static int dptxport_call(struct apple_epic_service *service, u32 idx,
478*5dd0baa8Skettenis 			 const void *data, size_t data_size, void *reply,
479*5dd0baa8Skettenis 			 size_t reply_size)
480*5dd0baa8Skettenis {
481*5dd0baa8Skettenis 	struct dptx_port *dptx = service->cookie;
482*5dd0baa8Skettenis 	trace_dptxport_apcall(dptx, idx, data_size);
483*5dd0baa8Skettenis 
484*5dd0baa8Skettenis 	switch (idx) {
485*5dd0baa8Skettenis 	case DPTX_APCALL_WILL_CHANGE_LINKG_CONFIG:
486*5dd0baa8Skettenis 		return dptxport_call_will_change_link_config(service);
487*5dd0baa8Skettenis 	case DPTX_APCALL_DID_CHANGE_LINK_CONFIG:
488*5dd0baa8Skettenis 		return dptxport_call_did_change_link_config(service);
489*5dd0baa8Skettenis 	case DPTX_APCALL_GET_MAX_LINK_RATE:
490*5dd0baa8Skettenis 		return dptxport_call_get_max_link_rate(service, reply,
491*5dd0baa8Skettenis 						       reply_size);
492*5dd0baa8Skettenis 	case DPTX_APCALL_GET_LINK_RATE:
493*5dd0baa8Skettenis 		return dptxport_call_get_link_rate(service, reply, reply_size);
494*5dd0baa8Skettenis 	case DPTX_APCALL_SET_LINK_RATE:
495*5dd0baa8Skettenis 		return dptxport_call_set_link_rate(service, data, data_size,
496*5dd0baa8Skettenis 						   reply, reply_size);
497*5dd0baa8Skettenis 	case DPTX_APCALL_GET_MAX_LANE_COUNT:
498*5dd0baa8Skettenis 		return dptxport_call_get_max_lane_count(service, reply, reply_size);
499*5dd0baa8Skettenis         case DPTX_APCALL_SET_ACTIVE_LANE_COUNT:
500*5dd0baa8Skettenis 		return dptxport_call_set_active_lane_count(service, data, data_size,
501*5dd0baa8Skettenis 							   reply, reply_size);
502*5dd0baa8Skettenis 	case DPTX_APCALL_GET_SUPPORTS_HPD:
503*5dd0baa8Skettenis 		return dptxport_call_get_supports_hpd(service, reply,
504*5dd0baa8Skettenis 						      reply_size);
505*5dd0baa8Skettenis 	case DPTX_APCALL_GET_SUPPORTS_DOWN_SPREAD:
506*5dd0baa8Skettenis 		return dptxport_call_get_supports_downspread(service, reply,
507*5dd0baa8Skettenis 							     reply_size);
508*5dd0baa8Skettenis 	case DPTX_APCALL_GET_MAX_DRIVE_SETTINGS:
509*5dd0baa8Skettenis 		return dptxport_call_get_max_drive_settings(service, reply,
510*5dd0baa8Skettenis 							    reply_size);
511*5dd0baa8Skettenis 	case DPTX_APCALL_GET_DRIVE_SETTINGS:
512*5dd0baa8Skettenis 		return dptxport_call_get_drive_settings(service, data, data_size,
513*5dd0baa8Skettenis 							reply, reply_size);
514*5dd0baa8Skettenis 	case DPTX_APCALL_SET_DRIVE_SETTINGS:
515*5dd0baa8Skettenis 		return dptxport_call_set_drive_settings(service, data, data_size,
516*5dd0baa8Skettenis 							reply, reply_size);
517*5dd0baa8Skettenis         case DPTX_APCALL_ACTIVATE:
518*5dd0baa8Skettenis 		return dptxport_call_activate(service, data, data_size,
519*5dd0baa8Skettenis 					      reply, reply_size);
520*5dd0baa8Skettenis 	case DPTX_APCALL_DEACTIVATE:
521*5dd0baa8Skettenis 		return dptxport_call_deactivate(service, data, data_size,
522*5dd0baa8Skettenis 						reply, reply_size);
523*5dd0baa8Skettenis 	default:
524*5dd0baa8Skettenis 		/* just try to ACK and hope for the best... */
525*5dd0baa8Skettenis 		dev_info(service->ep->dcp->dev, "DPTXPort: acking unhandled call %u\n",
526*5dd0baa8Skettenis 			idx);
527*5dd0baa8Skettenis 		memcpy(reply, data, min(reply_size, data_size));
528*5dd0baa8Skettenis 		if (reply_size >= 4)
529*5dd0baa8Skettenis 			memset(reply, 0, 4);
530*5dd0baa8Skettenis 		return 0;
531*5dd0baa8Skettenis 	}
532*5dd0baa8Skettenis }
533*5dd0baa8Skettenis 
dptxport_init(struct apple_epic_service * service,const char * name,const char * class,s64 unit)534*5dd0baa8Skettenis static void dptxport_init(struct apple_epic_service *service, const char *name,
535*5dd0baa8Skettenis 			  const char *class, s64 unit)
536*5dd0baa8Skettenis {
537*5dd0baa8Skettenis 
538*5dd0baa8Skettenis 	if (strcmp(name, "dcpdptx-port-epic"))
539*5dd0baa8Skettenis 		return;
540*5dd0baa8Skettenis 	if (strcmp(class, "AppleDCPDPTXRemotePort"))
541*5dd0baa8Skettenis 		return;
542*5dd0baa8Skettenis 
543*5dd0baa8Skettenis 	trace_dptxport_init(service->ep->dcp, unit);
544*5dd0baa8Skettenis 
545*5dd0baa8Skettenis 	switch (unit) {
546*5dd0baa8Skettenis 	case 0:
547*5dd0baa8Skettenis 	case 1:
548*5dd0baa8Skettenis 		if (service->ep->dcp->dptxport[unit].enabled) {
549*5dd0baa8Skettenis 			dev_err(service->ep->dcp->dev,
550*5dd0baa8Skettenis 				"DPTXPort: unit %lld already exists\n", unit);
551*5dd0baa8Skettenis 			return;
552*5dd0baa8Skettenis 		}
553*5dd0baa8Skettenis 		service->ep->dcp->dptxport[unit].unit = unit;
554*5dd0baa8Skettenis 		service->ep->dcp->dptxport[unit].service = service;
555*5dd0baa8Skettenis 		service->ep->dcp->dptxport[unit].enabled = true;
556*5dd0baa8Skettenis 		service->cookie = (void *)&service->ep->dcp->dptxport[unit];
557*5dd0baa8Skettenis 		complete(&service->ep->dcp->dptxport[unit].enable_completion);
558*5dd0baa8Skettenis 		break;
559*5dd0baa8Skettenis 	default:
560*5dd0baa8Skettenis 		dev_err(service->ep->dcp->dev, "DPTXPort: invalid unit %lld\n",
561*5dd0baa8Skettenis 			unit);
562*5dd0baa8Skettenis 	}
563*5dd0baa8Skettenis }
564*5dd0baa8Skettenis 
565*5dd0baa8Skettenis static const struct apple_epic_service_ops dptxep_ops[] = {
566*5dd0baa8Skettenis 	{
567*5dd0baa8Skettenis 		.name = "AppleDCPDPTXRemotePort",
568*5dd0baa8Skettenis 		.init = dptxport_init,
569*5dd0baa8Skettenis 		.call = dptxport_call,
570*5dd0baa8Skettenis 	},
571*5dd0baa8Skettenis 	{}
572*5dd0baa8Skettenis };
573*5dd0baa8Skettenis 
dptxep_init(struct apple_dcp * dcp)574*5dd0baa8Skettenis int dptxep_init(struct apple_dcp *dcp)
575*5dd0baa8Skettenis {
576*5dd0baa8Skettenis 	int ret;
577*5dd0baa8Skettenis 	u32 port;
578*5dd0baa8Skettenis 	unsigned long timeout = msecs_to_jiffies(1000);
579*5dd0baa8Skettenis 
580*5dd0baa8Skettenis 	init_completion(&dcp->dptxport[0].enable_completion);
581*5dd0baa8Skettenis 	init_completion(&dcp->dptxport[1].enable_completion);
582*5dd0baa8Skettenis 	init_completion(&dcp->dptxport[0].linkcfg_completion);
583*5dd0baa8Skettenis 	init_completion(&dcp->dptxport[1].linkcfg_completion);
584*5dd0baa8Skettenis 
585*5dd0baa8Skettenis 	dcp->dptxep = afk_init(dcp, DPTX_ENDPOINT, dptxep_ops);
586*5dd0baa8Skettenis 	if (IS_ERR(dcp->dptxep))
587*5dd0baa8Skettenis 		return PTR_ERR(dcp->dptxep);
588*5dd0baa8Skettenis 
589*5dd0baa8Skettenis 	ret = afk_start(dcp->dptxep);
590*5dd0baa8Skettenis 	if (ret)
591*5dd0baa8Skettenis 		return ret;
592*5dd0baa8Skettenis 
593*5dd0baa8Skettenis 	for (port = 0; port < dcp->hw.num_dptx_ports; port++) {
594*5dd0baa8Skettenis 		ret = wait_for_completion_timeout(&dcp->dptxport[port].enable_completion,
595*5dd0baa8Skettenis 						timeout);
596*5dd0baa8Skettenis 		if (!ret)
597*5dd0baa8Skettenis 			return -ETIMEDOUT;
598*5dd0baa8Skettenis 		else if (ret < 0)
599*5dd0baa8Skettenis 			return ret;
600*5dd0baa8Skettenis 		timeout = ret;
601*5dd0baa8Skettenis 	}
602*5dd0baa8Skettenis 
603*5dd0baa8Skettenis 	return 0;
604*5dd0baa8Skettenis }
605