^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (C) 2018-2020 Broadcom */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/iopoll.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/reset-controller.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #define BRCM_RESCAL_START 0x0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #define BRCM_RESCAL_START_BIT BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #define BRCM_RESCAL_CTRL 0x4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #define BRCM_RESCAL_STATUS 0x8
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define BRCM_RESCAL_STATUS_BIT BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) struct brcm_rescal_reset {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) void __iomem *base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct reset_controller_dev rcdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static int brcm_rescal_reset_set(struct reset_controller_dev *rcdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) unsigned long id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) struct brcm_rescal_reset *data =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) container_of(rcdev, struct brcm_rescal_reset, rcdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) void __iomem *base = data->base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) reg = readl(base + BRCM_RESCAL_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) writel(reg | BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) reg = readl(base + BRCM_RESCAL_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) if (!(reg & BRCM_RESCAL_START_BIT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) dev_err(data->dev, "failed to start SATA/PCIe rescal\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) return -EIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) ret = readl_poll_timeout(base + BRCM_RESCAL_STATUS, reg,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) (reg & BRCM_RESCAL_STATUS_BIT), 100, 1000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) dev_err(data->dev, "time out on SATA/PCIe rescal\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) reg = readl(base + BRCM_RESCAL_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) writel(reg & ~BRCM_RESCAL_START_BIT, base + BRCM_RESCAL_START);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) dev_dbg(data->dev, "SATA/PCIe rescal success\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) static int brcm_rescal_reset_xlate(struct reset_controller_dev *rcdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) const struct of_phandle_args *reset_spec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) /* This is needed if #reset-cells == 0. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) static const struct reset_control_ops brcm_rescal_reset_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) .reset = brcm_rescal_reset_set,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static int brcm_rescal_reset_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct brcm_rescal_reset *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct resource *res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if (!data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) data->base = devm_ioremap_resource(&pdev->dev, res);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (IS_ERR(data->base))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return PTR_ERR(data->base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) data->rcdev.owner = THIS_MODULE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) data->rcdev.nr_resets = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) data->rcdev.ops = &brcm_rescal_reset_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) data->rcdev.of_node = pdev->dev.of_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) data->rcdev.of_xlate = brcm_rescal_reset_xlate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) data->dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) return devm_reset_controller_register(&pdev->dev, &data->rcdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) static const struct of_device_id brcm_rescal_reset_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) { .compatible = "brcm,bcm7216-pcie-sata-rescal" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) { },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) MODULE_DEVICE_TABLE(of, brcm_rescal_reset_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static struct platform_driver brcm_rescal_reset_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) .probe = brcm_rescal_reset_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) .name = "brcm-rescal-reset",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) .of_match_table = brcm_rescal_reset_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) module_platform_driver(brcm_rescal_reset_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) MODULE_AUTHOR("Broadcom");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) MODULE_DESCRIPTION("Broadcom SATA/PCIe rescal reset controller");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) MODULE_LICENSE("GPL v2");