bt1-apb.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC
  4. *
  5. * Authors:
  6. * Serge Semin <[email protected]>
  7. *
  8. * Baikal-T1 APB-bus driver
  9. */
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <linux/types.h>
  13. #include <linux/device.h>
  14. #include <linux/atomic.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/interrupt.h>
  17. #include <linux/io.h>
  18. #include <linux/nmi.h>
  19. #include <linux/of.h>
  20. #include <linux/regmap.h>
  21. #include <linux/clk.h>
  22. #include <linux/reset.h>
  23. #include <linux/time64.h>
  24. #include <linux/clk.h>
  25. #include <linux/sysfs.h>
  26. #define APB_EHB_ISR 0x00
  27. #define APB_EHB_ISR_PENDING BIT(0)
  28. #define APB_EHB_ISR_MASK BIT(1)
  29. #define APB_EHB_ADDR 0x04
  30. #define APB_EHB_TIMEOUT 0x08
  31. #define APB_EHB_TIMEOUT_MIN 0x000003FFU
  32. #define APB_EHB_TIMEOUT_MAX 0xFFFFFFFFU
  33. /*
  34. * struct bt1_apb - Baikal-T1 APB EHB private data
  35. * @dev: Pointer to the device structure.
  36. * @regs: APB EHB registers map.
  37. * @res: No-device error injection memory region.
  38. * @irq: Errors IRQ number.
  39. * @rate: APB-bus reference clock rate.
  40. * @pclk: APB-reference clock.
  41. * @prst: APB domain reset line.
  42. * @count: Number of errors detected.
  43. */
  44. struct bt1_apb {
  45. struct device *dev;
  46. struct regmap *regs;
  47. void __iomem *res;
  48. int irq;
  49. unsigned long rate;
  50. struct clk *pclk;
  51. struct reset_control *prst;
  52. atomic_t count;
  53. };
  54. static const struct regmap_config bt1_apb_regmap_cfg = {
  55. .reg_bits = 32,
  56. .val_bits = 32,
  57. .reg_stride = 4,
  58. .max_register = APB_EHB_TIMEOUT,
  59. .fast_io = true
  60. };
  61. static inline unsigned long bt1_apb_n_to_timeout_us(struct bt1_apb *apb, u32 n)
  62. {
  63. u64 timeout = (u64)n * USEC_PER_SEC;
  64. do_div(timeout, apb->rate);
  65. return timeout;
  66. }
  67. static inline unsigned long bt1_apb_timeout_to_n_us(struct bt1_apb *apb,
  68. unsigned long timeout)
  69. {
  70. u64 n = (u64)timeout * apb->rate;
  71. do_div(n, USEC_PER_SEC);
  72. return n;
  73. }
  74. static irqreturn_t bt1_apb_isr(int irq, void *data)
  75. {
  76. struct bt1_apb *apb = data;
  77. u32 addr = 0;
  78. regmap_read(apb->regs, APB_EHB_ADDR, &addr);
  79. dev_crit_ratelimited(apb->dev,
  80. "APB-bus fault %d: Slave access timeout at 0x%08x\n",
  81. atomic_inc_return(&apb->count),
  82. addr);
  83. /*
  84. * Print backtrace on each CPU. This might be pointless if the fault
  85. * has happened on the same CPU as the IRQ handler is executed or
  86. * the other core proceeded further execution despite the error.
  87. * But if it's not, by looking at the trace we would get straight to
  88. * the cause of the problem.
  89. */
  90. trigger_all_cpu_backtrace();
  91. regmap_update_bits(apb->regs, APB_EHB_ISR, APB_EHB_ISR_PENDING, 0);
  92. return IRQ_HANDLED;
  93. }
  94. static void bt1_apb_clear_data(void *data)
  95. {
  96. struct bt1_apb *apb = data;
  97. struct platform_device *pdev = to_platform_device(apb->dev);
  98. platform_set_drvdata(pdev, NULL);
  99. }
  100. static struct bt1_apb *bt1_apb_create_data(struct platform_device *pdev)
  101. {
  102. struct device *dev = &pdev->dev;
  103. struct bt1_apb *apb;
  104. int ret;
  105. apb = devm_kzalloc(dev, sizeof(*apb), GFP_KERNEL);
  106. if (!apb)
  107. return ERR_PTR(-ENOMEM);
  108. ret = devm_add_action(dev, bt1_apb_clear_data, apb);
  109. if (ret) {
  110. dev_err(dev, "Can't add APB EHB data clear action\n");
  111. return ERR_PTR(ret);
  112. }
  113. apb->dev = dev;
  114. atomic_set(&apb->count, 0);
  115. platform_set_drvdata(pdev, apb);
  116. return apb;
  117. }
  118. static int bt1_apb_request_regs(struct bt1_apb *apb)
  119. {
  120. struct platform_device *pdev = to_platform_device(apb->dev);
  121. void __iomem *regs;
  122. regs = devm_platform_ioremap_resource_byname(pdev, "ehb");
  123. if (IS_ERR(regs)) {
  124. dev_err(apb->dev, "Couldn't map APB EHB registers\n");
  125. return PTR_ERR(regs);
  126. }
  127. apb->regs = devm_regmap_init_mmio(apb->dev, regs, &bt1_apb_regmap_cfg);
  128. if (IS_ERR(apb->regs)) {
  129. dev_err(apb->dev, "Couldn't create APB EHB regmap\n");
  130. return PTR_ERR(apb->regs);
  131. }
  132. apb->res = devm_platform_ioremap_resource_byname(pdev, "nodev");
  133. if (IS_ERR(apb->res))
  134. dev_err(apb->dev, "Couldn't map reserved region\n");
  135. return PTR_ERR_OR_ZERO(apb->res);
  136. }
  137. static int bt1_apb_request_rst(struct bt1_apb *apb)
  138. {
  139. int ret;
  140. apb->prst = devm_reset_control_get_optional_exclusive(apb->dev, "prst");
  141. if (IS_ERR(apb->prst))
  142. return dev_err_probe(apb->dev, PTR_ERR(apb->prst),
  143. "Couldn't get reset control line\n");
  144. ret = reset_control_deassert(apb->prst);
  145. if (ret)
  146. dev_err(apb->dev, "Failed to deassert the reset line\n");
  147. return ret;
  148. }
  149. static void bt1_apb_disable_clk(void *data)
  150. {
  151. struct bt1_apb *apb = data;
  152. clk_disable_unprepare(apb->pclk);
  153. }
  154. static int bt1_apb_request_clk(struct bt1_apb *apb)
  155. {
  156. int ret;
  157. apb->pclk = devm_clk_get(apb->dev, "pclk");
  158. if (IS_ERR(apb->pclk))
  159. return dev_err_probe(apb->dev, PTR_ERR(apb->pclk),
  160. "Couldn't get APB clock descriptor\n");
  161. ret = clk_prepare_enable(apb->pclk);
  162. if (ret) {
  163. dev_err(apb->dev, "Couldn't enable the APB clock\n");
  164. return ret;
  165. }
  166. ret = devm_add_action_or_reset(apb->dev, bt1_apb_disable_clk, apb);
  167. if (ret) {
  168. dev_err(apb->dev, "Can't add APB EHB clocks disable action\n");
  169. return ret;
  170. }
  171. apb->rate = clk_get_rate(apb->pclk);
  172. if (!apb->rate) {
  173. dev_err(apb->dev, "Invalid clock rate\n");
  174. return -EINVAL;
  175. }
  176. return 0;
  177. }
  178. static void bt1_apb_clear_irq(void *data)
  179. {
  180. struct bt1_apb *apb = data;
  181. regmap_update_bits(apb->regs, APB_EHB_ISR, APB_EHB_ISR_MASK, 0);
  182. }
  183. static int bt1_apb_request_irq(struct bt1_apb *apb)
  184. {
  185. struct platform_device *pdev = to_platform_device(apb->dev);
  186. int ret;
  187. apb->irq = platform_get_irq(pdev, 0);
  188. if (apb->irq < 0)
  189. return apb->irq;
  190. ret = devm_request_irq(apb->dev, apb->irq, bt1_apb_isr, IRQF_SHARED,
  191. "bt1-apb", apb);
  192. if (ret) {
  193. dev_err(apb->dev, "Couldn't request APB EHB IRQ\n");
  194. return ret;
  195. }
  196. ret = devm_add_action(apb->dev, bt1_apb_clear_irq, apb);
  197. if (ret) {
  198. dev_err(apb->dev, "Can't add APB EHB IRQs clear action\n");
  199. return ret;
  200. }
  201. /* Unmask IRQ and clear it' pending flag. */
  202. regmap_update_bits(apb->regs, APB_EHB_ISR,
  203. APB_EHB_ISR_PENDING | APB_EHB_ISR_MASK,
  204. APB_EHB_ISR_MASK);
  205. return 0;
  206. }
  207. static ssize_t count_show(struct device *dev, struct device_attribute *attr,
  208. char *buf)
  209. {
  210. struct bt1_apb *apb = dev_get_drvdata(dev);
  211. return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&apb->count));
  212. }
  213. static DEVICE_ATTR_RO(count);
  214. static ssize_t timeout_show(struct device *dev, struct device_attribute *attr,
  215. char *buf)
  216. {
  217. struct bt1_apb *apb = dev_get_drvdata(dev);
  218. unsigned long timeout;
  219. int ret;
  220. u32 n;
  221. ret = regmap_read(apb->regs, APB_EHB_TIMEOUT, &n);
  222. if (ret)
  223. return ret;
  224. timeout = bt1_apb_n_to_timeout_us(apb, n);
  225. return scnprintf(buf, PAGE_SIZE, "%lu\n", timeout);
  226. }
  227. static ssize_t timeout_store(struct device *dev,
  228. struct device_attribute *attr,
  229. const char *buf, size_t count)
  230. {
  231. struct bt1_apb *apb = dev_get_drvdata(dev);
  232. unsigned long timeout;
  233. int ret;
  234. u32 n;
  235. if (kstrtoul(buf, 0, &timeout) < 0)
  236. return -EINVAL;
  237. n = bt1_apb_timeout_to_n_us(apb, timeout);
  238. n = clamp(n, APB_EHB_TIMEOUT_MIN, APB_EHB_TIMEOUT_MAX);
  239. ret = regmap_write(apb->regs, APB_EHB_TIMEOUT, n);
  240. return ret ?: count;
  241. }
  242. static DEVICE_ATTR_RW(timeout);
  243. static ssize_t inject_error_show(struct device *dev,
  244. struct device_attribute *attr, char *buf)
  245. {
  246. return scnprintf(buf, PAGE_SIZE, "Error injection: nodev irq\n");
  247. }
  248. static ssize_t inject_error_store(struct device *dev,
  249. struct device_attribute *attr,
  250. const char *data, size_t count)
  251. {
  252. struct bt1_apb *apb = dev_get_drvdata(dev);
  253. /*
  254. * Either dummy read from the unmapped address in the APB IO area
  255. * or manually set the IRQ status.
  256. */
  257. if (sysfs_streq(data, "nodev"))
  258. readl(apb->res);
  259. else if (sysfs_streq(data, "irq"))
  260. regmap_update_bits(apb->regs, APB_EHB_ISR, APB_EHB_ISR_PENDING,
  261. APB_EHB_ISR_PENDING);
  262. else
  263. return -EINVAL;
  264. return count;
  265. }
  266. static DEVICE_ATTR_RW(inject_error);
  267. static struct attribute *bt1_apb_sysfs_attrs[] = {
  268. &dev_attr_count.attr,
  269. &dev_attr_timeout.attr,
  270. &dev_attr_inject_error.attr,
  271. NULL
  272. };
  273. ATTRIBUTE_GROUPS(bt1_apb_sysfs);
  274. static void bt1_apb_remove_sysfs(void *data)
  275. {
  276. struct bt1_apb *apb = data;
  277. device_remove_groups(apb->dev, bt1_apb_sysfs_groups);
  278. }
  279. static int bt1_apb_init_sysfs(struct bt1_apb *apb)
  280. {
  281. int ret;
  282. ret = device_add_groups(apb->dev, bt1_apb_sysfs_groups);
  283. if (ret) {
  284. dev_err(apb->dev, "Failed to create EHB APB sysfs nodes\n");
  285. return ret;
  286. }
  287. ret = devm_add_action_or_reset(apb->dev, bt1_apb_remove_sysfs, apb);
  288. if (ret)
  289. dev_err(apb->dev, "Can't add APB EHB sysfs remove action\n");
  290. return ret;
  291. }
  292. static int bt1_apb_probe(struct platform_device *pdev)
  293. {
  294. struct bt1_apb *apb;
  295. int ret;
  296. apb = bt1_apb_create_data(pdev);
  297. if (IS_ERR(apb))
  298. return PTR_ERR(apb);
  299. ret = bt1_apb_request_regs(apb);
  300. if (ret)
  301. return ret;
  302. ret = bt1_apb_request_rst(apb);
  303. if (ret)
  304. return ret;
  305. ret = bt1_apb_request_clk(apb);
  306. if (ret)
  307. return ret;
  308. ret = bt1_apb_request_irq(apb);
  309. if (ret)
  310. return ret;
  311. ret = bt1_apb_init_sysfs(apb);
  312. if (ret)
  313. return ret;
  314. return 0;
  315. }
  316. static const struct of_device_id bt1_apb_of_match[] = {
  317. { .compatible = "baikal,bt1-apb" },
  318. { }
  319. };
  320. MODULE_DEVICE_TABLE(of, bt1_apb_of_match);
  321. static struct platform_driver bt1_apb_driver = {
  322. .probe = bt1_apb_probe,
  323. .driver = {
  324. .name = "bt1-apb",
  325. .of_match_table = bt1_apb_of_match
  326. }
  327. };
  328. module_platform_driver(bt1_apb_driver);
  329. MODULE_AUTHOR("Serge Semin <[email protected]>");
  330. MODULE_DESCRIPTION("Baikal-T1 APB-bus driver");
  331. MODULE_LICENSE("GPL v2");