8e8e69d67e5fa (Thomas Gleixner 2019-05-29 07:17:59 -0700 1) // SPDX-License-Identifier: GPL-2.0-only
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 2) /*
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 3) * Copyright (c) 2017, National Instruments Corp.
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 4) * Copyright (c) 2017, Xilinx Inc
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 5) *
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 6) * FPGA Bridge Driver for the Xilinx LogiCORE Partial Reconfiguration
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 7) * Decoupler IP Core.
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 8) */
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 9)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 10) #include <linux/clk.h>
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 11) #include <linux/io.h>
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 12) #include <linux/kernel.h>
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 13) #include <linux/of_device.h>
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 14) #include <linux/module.h>
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 15) #include <linux/fpga/fpga-bridge.h>
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 16)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 17) #define CTRL_CMD_DECOUPLE BIT(0)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 18) #define CTRL_CMD_COUPLE 0
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 19) #define CTRL_OFFSET 0
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 20)
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 21) struct xlnx_config_data {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 22) const char *name;
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 23) };
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 24)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 25) struct xlnx_pr_decoupler_data {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 26) const struct xlnx_config_data *ipconfig;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 27) void __iomem *io_base;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 28) struct clk *clk;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 29) };
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 30)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 31) static inline void xlnx_pr_decoupler_write(struct xlnx_pr_decoupler_data *d,
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 32) u32 offset, u32 val)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 33) {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 34) writel(val, d->io_base + offset);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 35) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 36)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 37) static inline u32 xlnx_pr_decouple_read(const struct xlnx_pr_decoupler_data *d,
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 38) u32 offset)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 39) {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 40) return readl(d->io_base + offset);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 41) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 42)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 43) static int xlnx_pr_decoupler_enable_set(struct fpga_bridge *bridge, bool enable)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 44) {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 45) int err;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 46) struct xlnx_pr_decoupler_data *priv = bridge->priv;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 47)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 48) err = clk_enable(priv->clk);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 49) if (err)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 50) return err;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 51)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 52) if (enable)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 53) xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_COUPLE);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 54) else
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 55) xlnx_pr_decoupler_write(priv, CTRL_OFFSET, CTRL_CMD_DECOUPLE);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 56)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 57) clk_disable(priv->clk);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 58)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 59) return 0;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 60) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 61)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 62) static int xlnx_pr_decoupler_enable_show(struct fpga_bridge *bridge)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 63) {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 64) const struct xlnx_pr_decoupler_data *priv = bridge->priv;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 65) u32 status;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 66) int err;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 67)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 68) err = clk_enable(priv->clk);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 69) if (err)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 70) return err;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 71)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 72) status = readl(priv->io_base);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 73)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 74) clk_disable(priv->clk);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 75)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 76) return !status;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 77) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 78)
d8d9d936464a9 (Bhumika Goyal 2017-09-21 09:52:41 -0500 79) static const struct fpga_bridge_ops xlnx_pr_decoupler_br_ops = {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 80) .enable_set = xlnx_pr_decoupler_enable_set,
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 81) .enable_show = xlnx_pr_decoupler_enable_show,
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 82) };
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 83)
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 84) static const struct xlnx_config_data decoupler_config = {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 85) .name = "Xilinx PR Decoupler",
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 86) };
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 87)
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 88) static const struct xlnx_config_data shutdown_config = {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 89) .name = "Xilinx DFX AXI Shutdown Manager",
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 90) };
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 91)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 92) static const struct of_device_id xlnx_pr_decoupler_of_match[] = {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 93) { .compatible = "xlnx,pr-decoupler-1.00", .data = &decoupler_config },
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 94) { .compatible = "xlnx,pr-decoupler", .data = &decoupler_config },
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 95) { .compatible = "xlnx,dfx-axi-shutdown-manager-1.00",
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 96) .data = &shutdown_config },
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 97) { .compatible = "xlnx,dfx-axi-shutdown-manager",
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 98) .data = &shutdown_config },
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 99) {},
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 100) };
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 101) MODULE_DEVICE_TABLE(of, xlnx_pr_decoupler_of_match);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 102)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 103) static int xlnx_pr_decoupler_probe(struct platform_device *pdev)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 104) {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 105) struct device_node *np = pdev->dev.of_node;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 106) struct xlnx_pr_decoupler_data *priv;
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 107) struct fpga_bridge *br;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 108) int err;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 109) struct resource *res;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 110)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 111) priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 112) if (!priv)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 113) return -ENOMEM;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 114)
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 115) if (np) {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 116) const struct of_device_id *match;
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 117)
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 118) match = of_match_node(xlnx_pr_decoupler_of_match, np);
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 119) if (match && match->data)
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 120) priv->ipconfig = match->data;
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 121) }
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 122)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 123) res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 124) priv->io_base = devm_ioremap_resource(&pdev->dev, res);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 125) if (IS_ERR(priv->io_base))
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 126) return PTR_ERR(priv->io_base);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 127)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 128) priv->clk = devm_clk_get(&pdev->dev, "aclk");
b5c6ecfd471ea (Michal Simek 2021-02-04 14:36:11 +0100 129) if (IS_ERR(priv->clk))
b5c6ecfd471ea (Michal Simek 2021-02-04 14:36:11 +0100 130) return dev_err_probe(&pdev->dev, PTR_ERR(priv->clk),
b5c6ecfd471ea (Michal Simek 2021-02-04 14:36:11 +0100 131) "input clock not found\n");
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 132)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 133) err = clk_prepare_enable(priv->clk);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 134) if (err) {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 135) dev_err(&pdev->dev, "unable to enable clock\n");
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 136) return err;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 137) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 138)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 139) clk_disable(priv->clk);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 140)
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 141) br = devm_fpga_bridge_create(&pdev->dev, priv->ipconfig->name,
213befe049c70 (Alan Tull 2018-10-15 17:20:02 -0500 142) &xlnx_pr_decoupler_br_ops, priv);
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 143) if (!br) {
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 144) err = -ENOMEM;
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 145) goto err_clk;
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 146) }
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 147)
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 148) platform_set_drvdata(pdev, br);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 149)
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 150) err = fpga_bridge_register(br);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 151) if (err) {
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 152) dev_err(&pdev->dev, "unable to register %s",
30a2ac9a8bb5f (Nava kishore Manne 2021-02-11 10:41:48 +0530 153) priv->ipconfig->name);
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 154) goto err_clk;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 155) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 156)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 157) return 0;
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 158)
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 159) err_clk:
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 160) clk_unprepare(priv->clk);
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 161)
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 162) return err;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 163) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 164)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 165) static int xlnx_pr_decoupler_remove(struct platform_device *pdev)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 166) {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 167) struct fpga_bridge *bridge = platform_get_drvdata(pdev);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 168) struct xlnx_pr_decoupler_data *p = bridge->priv;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 169)
371cd1b1fdabb (Alan Tull 2018-05-16 18:49:56 -0500 170) fpga_bridge_unregister(bridge);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 171)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 172) clk_unprepare(p->clk);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 173)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 174) return 0;
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 175) }
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 176)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 177) static struct platform_driver xlnx_pr_decoupler_driver = {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 178) .probe = xlnx_pr_decoupler_probe,
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 179) .remove = xlnx_pr_decoupler_remove,
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 180) .driver = {
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 181) .name = "xlnx_pr_decoupler",
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 182) .of_match_table = of_match_ptr(xlnx_pr_decoupler_of_match),
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 183) },
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 184) };
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 185)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 186) module_platform_driver(xlnx_pr_decoupler_driver);
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 187)
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 188) MODULE_DESCRIPTION("Xilinx Partial Reconfiguration Decoupler");
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 189) MODULE_AUTHOR("Moritz Fischer <mdf@kernel.org>");
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 190) MODULE_AUTHOR("Michal Simek <michal.simek@xilinx.com>");
7e961c12be424 (Moritz Fischer 2017-03-24 10:33:21 -0500 191) MODULE_LICENSE("GPL v2");