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