Lines Matching +full:smc +full:- +full:reboot
1 // SPDX-License-Identifier: GPL-2.0-only OR MIT
3 * Apple SMC (System Management Controller) MFD driver
48 MFD_CELL_OF("macsmc-gpio", NULL, NULL, 0, 0, "apple,smc-gpio"),
49 MFD_CELL_OF("macsmc-reboot", NULL, NULL, 0, 0, "apple,smc-reboot"),
52 static int apple_smc_cmd_locked(struct apple_smc *smc, u64 cmd, u64 arg, in apple_smc_cmd_locked() argument
59 lockdep_assert_held(&smc->mutex); in apple_smc_cmd_locked()
61 if (smc->boot_stage != APPLE_SMC_INITIALIZED) in apple_smc_cmd_locked()
62 return -EIO; in apple_smc_cmd_locked()
63 if (smc->atomic_mode) in apple_smc_cmd_locked()
64 return -EIO; in apple_smc_cmd_locked()
66 reinit_completion(&smc->cmd_done); in apple_smc_cmd_locked()
68 smc->msg_id = (smc->msg_id + 1) & 0xf; in apple_smc_cmd_locked()
72 FIELD_PREP(SMC_ID, smc->msg_id) | in apple_smc_cmd_locked()
75 ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, false); in apple_smc_cmd_locked()
77 dev_err(smc->dev, "Failed to send command\n"); in apple_smc_cmd_locked()
81 if (wait_for_completion_timeout(&smc->cmd_done, msecs_to_jiffies(SMC_TIMEOUT_MS)) <= 0) { in apple_smc_cmd_locked()
82 dev_err(smc->dev, "Command timed out (%llx)", msg); in apple_smc_cmd_locked()
83 return -ETIMEDOUT; in apple_smc_cmd_locked()
86 if (FIELD_GET(SMC_ID, smc->cmd_ret) != smc->msg_id) { in apple_smc_cmd_locked()
87 dev_err(smc->dev, "Command sequence mismatch (expected %d, got %d)\n", in apple_smc_cmd_locked()
88 smc->msg_id, (unsigned int)FIELD_GET(SMC_ID, smc->cmd_ret)); in apple_smc_cmd_locked()
89 return -EIO; in apple_smc_cmd_locked()
92 result = FIELD_GET(SMC_RESULT, smc->cmd_ret); in apple_smc_cmd_locked()
94 return -EIO; in apple_smc_cmd_locked()
97 *ret_data = FIELD_GET(SMC_DATA, smc->cmd_ret); in apple_smc_cmd_locked()
99 return FIELD_GET(SMC_SIZE, smc->cmd_ret); in apple_smc_cmd_locked()
102 static int apple_smc_cmd(struct apple_smc *smc, u64 cmd, u64 arg, in apple_smc_cmd() argument
105 guard(mutex)(&smc->mutex); in apple_smc_cmd()
107 return apple_smc_cmd_locked(smc, cmd, arg, size, wsize, ret_data); in apple_smc_cmd()
110 static int apple_smc_rw_locked(struct apple_smc *smc, smc_key key, in apple_smc_rw_locked() argument
119 lockdep_assert_held(&smc->mutex); in apple_smc_rw_locked()
122 return -EINVAL; in apple_smc_rw_locked()
124 return -EINVAL; in apple_smc_rw_locked()
128 memcpy_toio(smc->shmem.iomem, wbuf, wsize); in apple_smc_rw_locked()
133 memcpy_toio(smc->shmem.iomem, wbuf, wsize); in apple_smc_rw_locked()
136 * looks silly but that's how the SMC protocol works ¯\_(ツ)_/¯ in apple_smc_rw_locked()
145 return -EINVAL; in apple_smc_rw_locked()
148 ret = apple_smc_cmd_locked(smc, cmd, key, smc_size, smc_wsize, &rdata); in apple_smc_rw_locked()
162 memcpy_fromio(rbuf, smc->shmem.iomem, rsize); in apple_smc_rw_locked()
168 int apple_smc_read(struct apple_smc *smc, smc_key key, void *buf, size_t size) in apple_smc_read() argument
170 guard(mutex)(&smc->mutex); in apple_smc_read()
172 return apple_smc_rw_locked(smc, key, NULL, 0, buf, size); in apple_smc_read()
176 int apple_smc_write(struct apple_smc *smc, smc_key key, void *buf, size_t size) in apple_smc_write() argument
178 guard(mutex)(&smc->mutex); in apple_smc_write()
180 return apple_smc_rw_locked(smc, key, buf, size, NULL, 0); in apple_smc_write()
184 int apple_smc_rw(struct apple_smc *smc, smc_key key, void *wbuf, size_t wsize, in apple_smc_rw() argument
187 guard(mutex)(&smc->mutex); in apple_smc_rw()
189 return apple_smc_rw_locked(smc, key, wbuf, wsize, rbuf, rsize); in apple_smc_rw()
193 int apple_smc_get_key_by_index(struct apple_smc *smc, int index, smc_key *key) in apple_smc_get_key_by_index() argument
197 ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_BY_INDEX, index, 0, 0, key); in apple_smc_get_key_by_index()
204 int apple_smc_get_key_info(struct apple_smc *smc, smc_key key, struct apple_smc_key_info *info) in apple_smc_get_key_info() argument
209 ret = apple_smc_cmd(smc, SMC_MSG_GET_KEY_INFO, key, 0, 0, NULL); in apple_smc_get_key_info()
211 memcpy_fromio(key_info, smc->shmem.iomem, sizeof(key_info)); in apple_smc_get_key_info()
212 info->size = key_info[0]; in apple_smc_get_key_info()
213 info->type_code = get_unaligned_be32(&key_info[1]); in apple_smc_get_key_info()
214 info->flags = key_info[5]; in apple_smc_get_key_info()
220 int apple_smc_enter_atomic(struct apple_smc *smc) in apple_smc_enter_atomic() argument
222 guard(mutex)(&smc->mutex); in apple_smc_enter_atomic()
228 * because we're about to shut down or reboot anyway. in apple_smc_enter_atomic()
230 * smc->mutex again. in apple_smc_enter_atomic()
234 apple_smc_rw_locked(smc, SMC_KEY(NTAP), &flag, sizeof(flag), NULL, 0); in apple_smc_enter_atomic()
236 smc->atomic_mode = true; in apple_smc_enter_atomic()
242 int apple_smc_write_atomic(struct apple_smc *smc, smc_key key, void *buf, size_t size) in apple_smc_write_atomic() argument
244 guard(spinlock_irqsave)(&smc->lock); in apple_smc_write_atomic()
250 return -EINVAL; in apple_smc_write_atomic()
252 if (smc->boot_stage != APPLE_SMC_INITIALIZED) in apple_smc_write_atomic()
253 return -EIO; in apple_smc_write_atomic()
254 if (!smc->atomic_mode) in apple_smc_write_atomic()
255 return -EIO; in apple_smc_write_atomic()
257 memcpy_toio(smc->shmem.iomem, buf, size); in apple_smc_write_atomic()
258 smc->msg_id = (smc->msg_id + 1) & 0xf; in apple_smc_write_atomic()
261 FIELD_PREP(SMC_ID, smc->msg_id) | in apple_smc_write_atomic()
263 smc->atomic_pending = true; in apple_smc_write_atomic()
265 ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, msg, NULL, true); in apple_smc_write_atomic()
267 dev_err(smc->dev, "Failed to send command (%d)\n", ret); in apple_smc_write_atomic()
271 while (smc->atomic_pending) { in apple_smc_write_atomic()
272 ret = apple_rtkit_poll(smc->rtk); in apple_smc_write_atomic()
274 dev_err(smc->dev, "RTKit poll failed (%llx)", msg); in apple_smc_write_atomic()
280 if (FIELD_GET(SMC_ID, smc->cmd_ret) != smc->msg_id) { in apple_smc_write_atomic()
281 dev_err(smc->dev, "Command sequence mismatch (expected %d, got %d)\n", in apple_smc_write_atomic()
282 smc->msg_id, (unsigned int)FIELD_GET(SMC_ID, smc->cmd_ret)); in apple_smc_write_atomic()
283 return -EIO; in apple_smc_write_atomic()
286 result = FIELD_GET(SMC_RESULT, smc->cmd_ret); in apple_smc_write_atomic()
288 return -EIO; in apple_smc_write_atomic()
290 return FIELD_GET(SMC_SIZE, smc->cmd_ret); in apple_smc_write_atomic()
296 struct apple_smc *smc = cookie; in apple_smc_rtkit_crashed() local
298 smc->boot_stage = APPLE_SMC_ERROR_CRASHED; in apple_smc_rtkit_crashed()
299 dev_err(smc->dev, "SMC crashed! Your system will reboot in a few seconds...\n"); in apple_smc_rtkit_crashed()
304 struct apple_smc *smc = cookie; in apple_smc_rtkit_shmem_setup() local
307 if (!bfr->iova) { in apple_smc_rtkit_shmem_setup()
308 dev_err(smc->dev, "RTKit wants a RAM buffer\n"); in apple_smc_rtkit_shmem_setup()
309 return -EIO; in apple_smc_rtkit_shmem_setup()
312 if (check_add_overflow(bfr->iova, bfr->size - 1, &bfr_end)) in apple_smc_rtkit_shmem_setup()
313 return -EFAULT; in apple_smc_rtkit_shmem_setup()
315 if (bfr->iova < smc->sram->start || bfr->iova > smc->sram->end || in apple_smc_rtkit_shmem_setup()
316 bfr_end > smc->sram->end) { in apple_smc_rtkit_shmem_setup()
317 dev_err(smc->dev, "RTKit buffer request outside SRAM region: [0x%llx, 0x%llx]\n", in apple_smc_rtkit_shmem_setup()
318 (unsigned long long)bfr->iova, in apple_smc_rtkit_shmem_setup()
320 return -EFAULT; in apple_smc_rtkit_shmem_setup()
323 bfr->iomem = smc->sram_base + (bfr->iova - smc->sram->start); in apple_smc_rtkit_shmem_setup()
324 bfr->is_mapped = true; in apple_smc_rtkit_shmem_setup()
331 struct apple_smc *smc = cookie; in apple_smc_rtkit_recv_early() local
334 dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint); in apple_smc_rtkit_recv_early()
338 if (smc->boot_stage == APPLE_SMC_BOOTING) { in apple_smc_rtkit_recv_early()
341 smc->shmem.iova = message; in apple_smc_rtkit_recv_early()
342 smc->shmem.size = SMC_SHMEM_SIZE; in apple_smc_rtkit_recv_early()
343 ret = apple_smc_rtkit_shmem_setup(smc, &smc->shmem); in apple_smc_rtkit_recv_early()
345 smc->boot_stage = APPLE_SMC_ERROR_NO_SHMEM; in apple_smc_rtkit_recv_early()
346 dev_err(smc->dev, "Failed to initialize shared memory (%d)\n", ret); in apple_smc_rtkit_recv_early()
348 smc->boot_stage = APPLE_SMC_INITIALIZED; in apple_smc_rtkit_recv_early()
350 complete(&smc->init_done); in apple_smc_rtkit_recv_early()
355 smc->cmd_ret = message; in apple_smc_rtkit_recv_early()
356 if (smc->atomic_pending) in apple_smc_rtkit_recv_early()
357 smc->atomic_pending = false; in apple_smc_rtkit_recv_early()
359 complete(&smc->cmd_done); in apple_smc_rtkit_recv_early()
367 struct apple_smc *smc = cookie; in apple_smc_rtkit_recv() local
370 dev_warn(smc->dev, "Received message for unknown endpoint 0x%x\n", endpoint); in apple_smc_rtkit_recv()
375 dev_warn(smc->dev, "Received unknown message from worker: 0x%llx\n", message); in apple_smc_rtkit_recv()
379 blocking_notifier_call_chain(&smc->event_handlers, FIELD_GET(SMC_DATA, message), NULL); in apple_smc_rtkit_recv()
391 struct apple_smc *smc = data; in apple_smc_rtkit_shutdown() local
393 /* Shut down SMC firmware, if it's not completely wedged */ in apple_smc_rtkit_shutdown()
394 if (apple_rtkit_is_running(smc->rtk)) in apple_smc_rtkit_shutdown()
395 apple_rtkit_quiesce(smc->rtk); in apple_smc_rtkit_shutdown()
400 struct apple_smc *smc = data; in apple_smc_disable_notifications() local
402 apple_smc_write_flag(smc, SMC_KEY(NTAP), false); in apple_smc_disable_notifications()
407 struct device *dev = &pdev->dev; in apple_smc_probe()
408 struct apple_smc *smc; in apple_smc_probe() local
412 smc = devm_kzalloc(dev, sizeof(*smc), GFP_KERNEL); in apple_smc_probe()
413 if (!smc) in apple_smc_probe()
414 return -ENOMEM; in apple_smc_probe()
416 smc->dev = &pdev->dev; in apple_smc_probe()
417 smc->sram_base = devm_platform_get_and_ioremap_resource(pdev, 1, &smc->sram); in apple_smc_probe()
418 if (IS_ERR(smc->sram_base)) in apple_smc_probe()
419 return dev_err_probe(dev, PTR_ERR(smc->sram_base), "Failed to map SRAM region"); in apple_smc_probe()
421 smc->rtk = devm_apple_rtkit_init(dev, smc, NULL, 0, &apple_smc_rtkit_ops); in apple_smc_probe()
422 if (IS_ERR(smc->rtk)) in apple_smc_probe()
423 return dev_err_probe(dev, PTR_ERR(smc->rtk), "Failed to initialize RTKit"); in apple_smc_probe()
425 smc->boot_stage = APPLE_SMC_BOOTING; in apple_smc_probe()
426 ret = apple_rtkit_wake(smc->rtk); in apple_smc_probe()
428 return dev_err_probe(dev, ret, "Failed to wake up SMC"); in apple_smc_probe()
430 ret = devm_add_action_or_reset(dev, apple_smc_rtkit_shutdown, smc); in apple_smc_probe()
434 ret = apple_rtkit_start_ep(smc->rtk, SMC_ENDPOINT); in apple_smc_probe()
436 return dev_err_probe(dev, ret, "Failed to start SMC endpoint"); in apple_smc_probe()
438 init_completion(&smc->init_done); in apple_smc_probe()
439 init_completion(&smc->cmd_done); in apple_smc_probe()
441 ret = apple_rtkit_send_message(smc->rtk, SMC_ENDPOINT, in apple_smc_probe()
446 if (wait_for_completion_timeout(&smc->init_done, msecs_to_jiffies(SMC_TIMEOUT_MS)) == 0) { in apple_smc_probe()
447 dev_err(dev, "Timed out initializing SMC"); in apple_smc_probe()
448 return -ETIMEDOUT; in apple_smc_probe()
451 if (smc->boot_stage != APPLE_SMC_INITIALIZED) { in apple_smc_probe()
452 dev_err(dev, "SMC failed to boot successfully, boot stage=%d\n", smc->boot_stage); in apple_smc_probe()
453 return -EIO; in apple_smc_probe()
456 dev_set_drvdata(&pdev->dev, smc); in apple_smc_probe()
457 BLOCKING_INIT_NOTIFIER_HEAD(&smc->event_handlers); in apple_smc_probe()
459 ret = apple_smc_read_u32(smc, SMC_KEY(#KEY), &count); in apple_smc_probe()
461 return dev_err_probe(smc->dev, ret, "Failed to get key count"); in apple_smc_probe()
462 smc->key_count = be32_to_cpu(count); in apple_smc_probe()
465 apple_smc_write_flag(smc, SMC_KEY(NTAP), true); in apple_smc_probe()
466 ret = devm_add_action_or_reset(dev, apple_smc_disable_notifications, smc); in apple_smc_probe()
470 ret = devm_mfd_add_devices(smc->dev, PLATFORM_DEVID_NONE, in apple_smc_probe()
474 return dev_err_probe(smc->dev, ret, "Failed to register sub-devices"); in apple_smc_probe()
481 { .compatible = "apple,smc" },
498 MODULE_DESCRIPTION("Apple SMC driver");