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/completion.h>
5*5dd0baa8Skettenis
6*5dd0baa8Skettenis #include "afk.h"
7*5dd0baa8Skettenis #include "dcp.h"
8*5dd0baa8Skettenis #include "parser.h"
9*5dd0baa8Skettenis
10*5dd0baa8Skettenis static bool enable_verbose_logging;
11*5dd0baa8Skettenis module_param(enable_verbose_logging, bool, 0644);
12*5dd0baa8Skettenis MODULE_PARM_DESC(enable_verbose_logging, "Enable DCP firmware verbose logging");
13*5dd0baa8Skettenis
14*5dd0baa8Skettenis /*
15*5dd0baa8Skettenis * Serialized setProperty("gAFKConfigLogMask", 0xffff) IPC call which
16*5dd0baa8Skettenis * will set the DCP firmware log level to the most verbose setting
17*5dd0baa8Skettenis */
18*5dd0baa8Skettenis #define SYSTEM_SET_PROPERTY 0x43
19*5dd0baa8Skettenis static const u8 setprop_gAFKConfigLogMask_ffff[] = {
20*5dd0baa8Skettenis 0x14, 0x00, 0x00, 0x00, 0x67, 0x41, 0x46, 0x4b, 0x43, 0x6f,
21*5dd0baa8Skettenis 0x6e, 0x66, 0x69, 0x67, 0x4c, 0x6f, 0x67, 0x4d, 0x61, 0x73,
22*5dd0baa8Skettenis 0x6b, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x40, 0x00,
23*5dd0baa8Skettenis 0x00, 0x84, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
24*5dd0baa8Skettenis };
25*5dd0baa8Skettenis
26*5dd0baa8Skettenis struct systemep_work {
27*5dd0baa8Skettenis struct apple_epic_service *service;
28*5dd0baa8Skettenis struct work_struct work;
29*5dd0baa8Skettenis };
30*5dd0baa8Skettenis
system_log_work(struct work_struct * work_)31*5dd0baa8Skettenis static void system_log_work(struct work_struct *work_)
32*5dd0baa8Skettenis {
33*5dd0baa8Skettenis struct systemep_work *work =
34*5dd0baa8Skettenis container_of(work_, struct systemep_work, work);
35*5dd0baa8Skettenis
36*5dd0baa8Skettenis afk_send_command(work->service, SYSTEM_SET_PROPERTY,
37*5dd0baa8Skettenis setprop_gAFKConfigLogMask_ffff,
38*5dd0baa8Skettenis sizeof(setprop_gAFKConfigLogMask_ffff), NULL,
39*5dd0baa8Skettenis sizeof(setprop_gAFKConfigLogMask_ffff), NULL);
40*5dd0baa8Skettenis complete(&work->service->ep->dcp->systemep_done);
41*5dd0baa8Skettenis kfree(work);
42*5dd0baa8Skettenis }
43*5dd0baa8Skettenis
system_init(struct apple_epic_service * service,const char * name,const char * class,s64 unit)44*5dd0baa8Skettenis static void system_init(struct apple_epic_service *service, const char *name,
45*5dd0baa8Skettenis const char *class, s64 unit)
46*5dd0baa8Skettenis {
47*5dd0baa8Skettenis struct systemep_work *work;
48*5dd0baa8Skettenis
49*5dd0baa8Skettenis if (!enable_verbose_logging)
50*5dd0baa8Skettenis return;
51*5dd0baa8Skettenis
52*5dd0baa8Skettenis /*
53*5dd0baa8Skettenis * We're called from the service message handler thread and can't
54*5dd0baa8Skettenis * dispatch blocking message from there.
55*5dd0baa8Skettenis */
56*5dd0baa8Skettenis work = kzalloc(sizeof(*work), GFP_KERNEL);
57*5dd0baa8Skettenis if (!work)
58*5dd0baa8Skettenis return;
59*5dd0baa8Skettenis
60*5dd0baa8Skettenis work->service = service;
61*5dd0baa8Skettenis INIT_WORK(&work->work, system_log_work);
62*5dd0baa8Skettenis schedule_work(&work->work);
63*5dd0baa8Skettenis }
64*5dd0baa8Skettenis
powerlog_init(struct apple_epic_service * service,const char * name,const char * class,s64 unit)65*5dd0baa8Skettenis static void powerlog_init(struct apple_epic_service *service, const char *name,
66*5dd0baa8Skettenis const char *class, s64 unit)
67*5dd0baa8Skettenis {
68*5dd0baa8Skettenis }
69*5dd0baa8Skettenis
powerlog_report(struct apple_epic_service * service,enum epic_subtype type,const void * data,size_t data_size)70*5dd0baa8Skettenis static int powerlog_report(struct apple_epic_service *service, enum epic_subtype type,
71*5dd0baa8Skettenis const void *data, size_t data_size)
72*5dd0baa8Skettenis {
73*5dd0baa8Skettenis struct dcp_system_ev_mnits mnits;
74*5dd0baa8Skettenis struct dcp_parse_ctx parse_ctx;
75*5dd0baa8Skettenis struct apple_dcp *dcp = service->ep->dcp;
76*5dd0baa8Skettenis int ret;
77*5dd0baa8Skettenis
78*5dd0baa8Skettenis dev_dbg(dcp->dev, "systemep[ch:%u]: report type:%02x len:%zu\n",
79*5dd0baa8Skettenis service->channel, type, data_size);
80*5dd0baa8Skettenis
81*5dd0baa8Skettenis if (type != EPIC_SUBTYPE_STD_SERVICE)
82*5dd0baa8Skettenis return 0;
83*5dd0baa8Skettenis
84*5dd0baa8Skettenis ret = parse(data, data_size, &parse_ctx);
85*5dd0baa8Skettenis if (ret) {
86*5dd0baa8Skettenis dev_warn(service->ep->dcp->dev, "systemep: failed to parse report: %d\n", ret);
87*5dd0baa8Skettenis return ret;
88*5dd0baa8Skettenis }
89*5dd0baa8Skettenis
90*5dd0baa8Skettenis ret = parse_system_log_mnits(&parse_ctx, &mnits);
91*5dd0baa8Skettenis if (ret) {
92*5dd0baa8Skettenis /* ignore parse errors in the case dcp sends unknown log events */
93*5dd0baa8Skettenis dev_dbg(dcp->dev, "systemep: failed to parse mNits event: %d\n", ret);
94*5dd0baa8Skettenis return 0;
95*5dd0baa8Skettenis }
96*5dd0baa8Skettenis
97*5dd0baa8Skettenis dev_dbg(dcp->dev, "systemep: mNits event: Nits: %u.%03u, iDAC: %u\n",
98*5dd0baa8Skettenis mnits.millinits / 1000, mnits.millinits % 1000, mnits.idac);
99*5dd0baa8Skettenis
100*5dd0baa8Skettenis dcp->brightness.nits = mnits.millinits / 1000;
101*5dd0baa8Skettenis
102*5dd0baa8Skettenis return 0;
103*5dd0baa8Skettenis }
104*5dd0baa8Skettenis
105*5dd0baa8Skettenis static const struct apple_epic_service_ops systemep_ops[] = {
106*5dd0baa8Skettenis {
107*5dd0baa8Skettenis .name = "system",
108*5dd0baa8Skettenis .init = system_init,
109*5dd0baa8Skettenis },
110*5dd0baa8Skettenis {
111*5dd0baa8Skettenis .name = "powerlog-service",
112*5dd0baa8Skettenis .init = powerlog_init,
113*5dd0baa8Skettenis .report = powerlog_report,
114*5dd0baa8Skettenis },
115*5dd0baa8Skettenis {}
116*5dd0baa8Skettenis };
117*5dd0baa8Skettenis
systemep_init(struct apple_dcp * dcp)118*5dd0baa8Skettenis int systemep_init(struct apple_dcp *dcp)
119*5dd0baa8Skettenis {
120*5dd0baa8Skettenis init_completion(&dcp->systemep_done);
121*5dd0baa8Skettenis
122*5dd0baa8Skettenis dcp->systemep = afk_init(dcp, SYSTEM_ENDPOINT, systemep_ops);
123*5dd0baa8Skettenis afk_start(dcp->systemep);
124*5dd0baa8Skettenis
125*5dd0baa8Skettenis if (!enable_verbose_logging)
126*5dd0baa8Skettenis return 0;
127*5dd0baa8Skettenis
128*5dd0baa8Skettenis /*
129*5dd0baa8Skettenis * Timeouts aren't really fatal here: in the worst case we just weren't
130*5dd0baa8Skettenis * able to enable additional debug prints inside DCP
131*5dd0baa8Skettenis */
132*5dd0baa8Skettenis if (!wait_for_completion_timeout(&dcp->systemep_done,
133*5dd0baa8Skettenis msecs_to_jiffies(MSEC_PER_SEC)))
134*5dd0baa8Skettenis dev_err(dcp->dev, "systemep: couldn't enable verbose logs\n");
135*5dd0baa8Skettenis
136*5dd0baa8Skettenis return 0;
137*5dd0baa8Skettenis }
138