18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Raspberry Pi 4 firmware reset driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2020 Nicolas Saenz Julienne <nsaenzjulienne@suse.de> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci#include <linux/delay.h> 88c2ecf20Sopenharmony_ci#include <linux/device.h> 98c2ecf20Sopenharmony_ci#include <linux/module.h> 108c2ecf20Sopenharmony_ci#include <linux/of.h> 118c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 128c2ecf20Sopenharmony_ci#include <linux/reset-controller.h> 138c2ecf20Sopenharmony_ci#include <soc/bcm2835/raspberrypi-firmware.h> 148c2ecf20Sopenharmony_ci#include <dt-bindings/reset/raspberrypi,firmware-reset.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistruct rpi_reset { 178c2ecf20Sopenharmony_ci struct reset_controller_dev rcdev; 188c2ecf20Sopenharmony_ci struct rpi_firmware *fw; 198c2ecf20Sopenharmony_ci}; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic inline struct rpi_reset *to_rpi(struct reset_controller_dev *rcdev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci return container_of(rcdev, struct rpi_reset, rcdev); 248c2ecf20Sopenharmony_ci} 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int rpi_reset_reset(struct reset_controller_dev *rcdev, unsigned long id) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct rpi_reset *priv = to_rpi(rcdev); 298c2ecf20Sopenharmony_ci u32 dev_addr; 308c2ecf20Sopenharmony_ci int ret; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci switch (id) { 338c2ecf20Sopenharmony_ci case RASPBERRYPI_FIRMWARE_RESET_ID_USB: 348c2ecf20Sopenharmony_ci /* 358c2ecf20Sopenharmony_ci * The Raspberry Pi 4 gets its USB functionality from VL805, a 368c2ecf20Sopenharmony_ci * PCIe chip that implements xHCI. After a PCI reset, VL805's 378c2ecf20Sopenharmony_ci * firmware may either be loaded directly from an EEPROM or, if 388c2ecf20Sopenharmony_ci * not present, by the SoC's co-processor, VideoCore. rpi's 398c2ecf20Sopenharmony_ci * VideoCore OS contains both the non public firmware load 408c2ecf20Sopenharmony_ci * logic and the VL805 firmware blob. This triggers the 418c2ecf20Sopenharmony_ci * aforementioned process. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * The pci device address is expected is expected by the 448c2ecf20Sopenharmony_ci * firmware encoded like this: 458c2ecf20Sopenharmony_ci * 468c2ecf20Sopenharmony_ci * PCI_BUS << 20 | PCI_SLOT << 15 | PCI_FUNC << 12 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * But since rpi's PCIe is hardwired, we know the address in 498c2ecf20Sopenharmony_ci * advance. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci dev_addr = 0x100000; 528c2ecf20Sopenharmony_ci ret = rpi_firmware_property(priv->fw, RPI_FIRMWARE_NOTIFY_XHCI_RESET, 538c2ecf20Sopenharmony_ci &dev_addr, sizeof(dev_addr)); 548c2ecf20Sopenharmony_ci if (ret) 558c2ecf20Sopenharmony_ci return ret; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci /* Wait for vl805 to startup */ 588c2ecf20Sopenharmony_ci usleep_range(200, 1000); 598c2ecf20Sopenharmony_ci break; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci default: 628c2ecf20Sopenharmony_ci return -EINVAL; 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic const struct reset_control_ops rpi_reset_ops = { 698c2ecf20Sopenharmony_ci .reset = rpi_reset_reset, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int rpi_reset_probe(struct platform_device *pdev) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 758c2ecf20Sopenharmony_ci struct rpi_firmware *fw; 768c2ecf20Sopenharmony_ci struct device_node *np; 778c2ecf20Sopenharmony_ci struct rpi_reset *priv; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci np = of_get_parent(dev->of_node); 808c2ecf20Sopenharmony_ci if (!np) { 818c2ecf20Sopenharmony_ci dev_err(dev, "Missing firmware node\n"); 828c2ecf20Sopenharmony_ci return -ENOENT; 838c2ecf20Sopenharmony_ci } 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci fw = rpi_firmware_get(np); 868c2ecf20Sopenharmony_ci of_node_put(np); 878c2ecf20Sopenharmony_ci if (!fw) 888c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 918c2ecf20Sopenharmony_ci if (!priv) 928c2ecf20Sopenharmony_ci return -ENOMEM; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci dev_set_drvdata(dev, priv); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci priv->fw = fw; 978c2ecf20Sopenharmony_ci priv->rcdev.owner = THIS_MODULE; 988c2ecf20Sopenharmony_ci priv->rcdev.nr_resets = RASPBERRYPI_FIRMWARE_RESET_NUM_IDS; 998c2ecf20Sopenharmony_ci priv->rcdev.ops = &rpi_reset_ops; 1008c2ecf20Sopenharmony_ci priv->rcdev.of_node = dev->of_node; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci return devm_reset_controller_register(dev, &priv->rcdev); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic const struct of_device_id rpi_reset_of_match[] = { 1068c2ecf20Sopenharmony_ci { .compatible = "raspberrypi,firmware-reset" }, 1078c2ecf20Sopenharmony_ci { /* sentinel */ } 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rpi_reset_of_match); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_cistatic struct platform_driver rpi_reset_driver = { 1128c2ecf20Sopenharmony_ci .probe = rpi_reset_probe, 1138c2ecf20Sopenharmony_ci .driver = { 1148c2ecf20Sopenharmony_ci .name = "raspberrypi-reset", 1158c2ecf20Sopenharmony_ci .of_match_table = rpi_reset_of_match, 1168c2ecf20Sopenharmony_ci }, 1178c2ecf20Sopenharmony_ci}; 1188c2ecf20Sopenharmony_cimodule_platform_driver(rpi_reset_driver); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de>"); 1218c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Raspberry Pi 4 firmware reset driver"); 1228c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 123