1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * LiteX SoC Controller Driver |
4 | * |
5 | * Copyright (C) 2020 Antmicro <www.antmicro.com> |
6 | * |
7 | */ |
8 | |
9 | #include <linux/litex.h> |
10 | #include <linux/device.h> |
11 | #include <linux/errno.h> |
12 | #include <linux/of.h> |
13 | #include <linux/platform_device.h> |
14 | #include <linux/printk.h> |
15 | #include <linux/module.h> |
16 | #include <linux/io.h> |
17 | #include <linux/reboot.h> |
18 | |
19 | /* reset register located at the base address */ |
20 | #define RESET_REG_OFF 0x00 |
21 | #define RESET_REG_VALUE 0x00000001 |
22 | |
23 | #define SCRATCH_REG_OFF 0x04 |
24 | #define SCRATCH_REG_VALUE 0x12345678 |
25 | #define SCRATCH_TEST_VALUE 0xdeadbeef |
26 | |
27 | /* |
28 | * Check LiteX CSR read/write access |
29 | * |
30 | * This function reads and writes a scratch register in order to verify if CSR |
31 | * access works. |
32 | * |
33 | * In case any problems are detected, the driver should panic. |
34 | * |
35 | * Access to the LiteX CSR is, by design, done in CPU native endianness. |
36 | * The driver should not dynamically configure access functions when |
37 | * the endianness mismatch is detected. Such situation indicates problems in |
38 | * the soft SoC design and should be solved at the LiteX generator level, |
39 | * not in the software. |
40 | */ |
41 | static int litex_check_csr_access(void __iomem *reg_addr) |
42 | { |
43 | unsigned long reg; |
44 | |
45 | reg = litex_read32(reg: reg_addr + SCRATCH_REG_OFF); |
46 | |
47 | if (reg != SCRATCH_REG_VALUE) { |
48 | panic(fmt: "Scratch register read error - the system is probably broken! Expected: 0x%x but got: 0x%lx" , |
49 | SCRATCH_REG_VALUE, reg); |
50 | return -EINVAL; |
51 | } |
52 | |
53 | litex_write32(reg: reg_addr + SCRATCH_REG_OFF, SCRATCH_TEST_VALUE); |
54 | reg = litex_read32(reg: reg_addr + SCRATCH_REG_OFF); |
55 | |
56 | if (reg != SCRATCH_TEST_VALUE) { |
57 | panic(fmt: "Scratch register write error - the system is probably broken! Expected: 0x%x but got: 0x%lx" , |
58 | SCRATCH_TEST_VALUE, reg); |
59 | return -EINVAL; |
60 | } |
61 | |
62 | /* restore original value of the SCRATCH register */ |
63 | litex_write32(reg: reg_addr + SCRATCH_REG_OFF, SCRATCH_REG_VALUE); |
64 | |
65 | pr_info("LiteX SoC Controller driver initialized" ); |
66 | |
67 | return 0; |
68 | } |
69 | |
70 | struct litex_soc_ctrl_device { |
71 | void __iomem *base; |
72 | struct notifier_block reset_nb; |
73 | }; |
74 | |
75 | static int litex_reset_handler(struct notifier_block *this, unsigned long mode, |
76 | void *cmd) |
77 | { |
78 | struct litex_soc_ctrl_device *soc_ctrl_dev = |
79 | container_of(this, struct litex_soc_ctrl_device, reset_nb); |
80 | |
81 | litex_write32(reg: soc_ctrl_dev->base + RESET_REG_OFF, RESET_REG_VALUE); |
82 | return NOTIFY_DONE; |
83 | } |
84 | |
85 | #ifdef CONFIG_OF |
86 | static const struct of_device_id litex_soc_ctrl_of_match[] = { |
87 | {.compatible = "litex,soc-controller" }, |
88 | {}, |
89 | }; |
90 | MODULE_DEVICE_TABLE(of, litex_soc_ctrl_of_match); |
91 | #endif /* CONFIG_OF */ |
92 | |
93 | static int litex_soc_ctrl_probe(struct platform_device *pdev) |
94 | { |
95 | struct litex_soc_ctrl_device *soc_ctrl_dev; |
96 | int error; |
97 | |
98 | soc_ctrl_dev = devm_kzalloc(dev: &pdev->dev, size: sizeof(*soc_ctrl_dev), GFP_KERNEL); |
99 | if (!soc_ctrl_dev) |
100 | return -ENOMEM; |
101 | |
102 | soc_ctrl_dev->base = devm_platform_ioremap_resource(pdev, index: 0); |
103 | if (IS_ERR(ptr: soc_ctrl_dev->base)) |
104 | return PTR_ERR(ptr: soc_ctrl_dev->base); |
105 | |
106 | error = litex_check_csr_access(reg_addr: soc_ctrl_dev->base); |
107 | if (error) |
108 | return error; |
109 | |
110 | platform_set_drvdata(pdev, data: soc_ctrl_dev); |
111 | |
112 | soc_ctrl_dev->reset_nb.notifier_call = litex_reset_handler; |
113 | soc_ctrl_dev->reset_nb.priority = 128; |
114 | error = register_restart_handler(&soc_ctrl_dev->reset_nb); |
115 | if (error) { |
116 | dev_warn(&pdev->dev, "cannot register restart handler: %d\n" , |
117 | error); |
118 | } |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | static void litex_soc_ctrl_remove(struct platform_device *pdev) |
124 | { |
125 | struct litex_soc_ctrl_device *soc_ctrl_dev = platform_get_drvdata(pdev); |
126 | |
127 | unregister_restart_handler(&soc_ctrl_dev->reset_nb); |
128 | } |
129 | |
130 | static struct platform_driver litex_soc_ctrl_driver = { |
131 | .driver = { |
132 | .name = "litex-soc-controller" , |
133 | .of_match_table = of_match_ptr(litex_soc_ctrl_of_match) |
134 | }, |
135 | .probe = litex_soc_ctrl_probe, |
136 | .remove_new = litex_soc_ctrl_remove, |
137 | }; |
138 | |
139 | module_platform_driver(litex_soc_ctrl_driver); |
140 | MODULE_DESCRIPTION("LiteX SoC Controller driver" ); |
141 | MODULE_AUTHOR("Antmicro <www.antmicro.com>" ); |
142 | MODULE_LICENSE("GPL v2" ); |
143 | |