18f93662dSSerge Semin // SPDX-License-Identifier: GPL-2.0-only 28f93662dSSerge Semin /* 38f93662dSSerge Semin * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC 48f93662dSSerge Semin * 58f93662dSSerge Semin * Authors: 68f93662dSSerge Semin * Serge Semin <Sergey.Semin@baikalelectronics.ru> 78f93662dSSerge Semin * 88f93662dSSerge Semin * Baikal-T1 APB-bus driver 98f93662dSSerge Semin */ 108f93662dSSerge Semin 118f93662dSSerge Semin #include <linux/kernel.h> 128f93662dSSerge Semin #include <linux/module.h> 138f93662dSSerge Semin #include <linux/types.h> 148f93662dSSerge Semin #include <linux/device.h> 158f93662dSSerge Semin #include <linux/atomic.h> 168f93662dSSerge Semin #include <linux/platform_device.h> 178f93662dSSerge Semin #include <linux/interrupt.h> 181c8ceb16SSerge Semin #include <linux/io.h> 198f93662dSSerge Semin #include <linux/nmi.h> 208f93662dSSerge Semin #include <linux/of.h> 218f93662dSSerge Semin #include <linux/regmap.h> 228f93662dSSerge Semin #include <linux/clk.h> 238f93662dSSerge Semin #include <linux/reset.h> 248f93662dSSerge Semin #include <linux/time64.h> 258f93662dSSerge Semin #include <linux/sysfs.h> 268f93662dSSerge Semin 278f93662dSSerge Semin #define APB_EHB_ISR 0x00 288f93662dSSerge Semin #define APB_EHB_ISR_PENDING BIT(0) 298f93662dSSerge Semin #define APB_EHB_ISR_MASK BIT(1) 308f93662dSSerge Semin #define APB_EHB_ADDR 0x04 318f93662dSSerge Semin #define APB_EHB_TIMEOUT 0x08 328f93662dSSerge Semin 338f93662dSSerge Semin #define APB_EHB_TIMEOUT_MIN 0x000003FFU 348f93662dSSerge Semin #define APB_EHB_TIMEOUT_MAX 0xFFFFFFFFU 358f93662dSSerge Semin 368f93662dSSerge Semin /* 378f93662dSSerge Semin * struct bt1_apb - Baikal-T1 APB EHB private data 388f93662dSSerge Semin * @dev: Pointer to the device structure. 398f93662dSSerge Semin * @regs: APB EHB registers map. 408f93662dSSerge Semin * @res: No-device error injection memory region. 418f93662dSSerge Semin * @irq: Errors IRQ number. 428f93662dSSerge Semin * @rate: APB-bus reference clock rate. 438f93662dSSerge Semin * @pclk: APB-reference clock. 448f93662dSSerge Semin * @prst: APB domain reset line. 458f93662dSSerge Semin * @count: Number of errors detected. 468f93662dSSerge Semin */ 478f93662dSSerge Semin struct bt1_apb { 488f93662dSSerge Semin struct device *dev; 498f93662dSSerge Semin 508f93662dSSerge Semin struct regmap *regs; 518f93662dSSerge Semin void __iomem *res; 528f93662dSSerge Semin int irq; 538f93662dSSerge Semin 548f93662dSSerge Semin unsigned long rate; 558f93662dSSerge Semin struct clk *pclk; 568f93662dSSerge Semin 578f93662dSSerge Semin struct reset_control *prst; 588f93662dSSerge Semin 598f93662dSSerge Semin atomic_t count; 608f93662dSSerge Semin }; 618f93662dSSerge Semin 628f93662dSSerge Semin static const struct regmap_config bt1_apb_regmap_cfg = { 638f93662dSSerge Semin .reg_bits = 32, 648f93662dSSerge Semin .val_bits = 32, 658f93662dSSerge Semin .reg_stride = 4, 668f93662dSSerge Semin .max_register = APB_EHB_TIMEOUT, 678f93662dSSerge Semin .fast_io = true 688f93662dSSerge Semin }; 698f93662dSSerge Semin 708f93662dSSerge Semin static inline unsigned long bt1_apb_n_to_timeout_us(struct bt1_apb *apb, u32 n) 718f93662dSSerge Semin { 728f93662dSSerge Semin u64 timeout = (u64)n * USEC_PER_SEC; 738f93662dSSerge Semin 748f93662dSSerge Semin do_div(timeout, apb->rate); 758f93662dSSerge Semin 768f93662dSSerge Semin return timeout; 778f93662dSSerge Semin 788f93662dSSerge Semin } 798f93662dSSerge Semin 808f93662dSSerge Semin static inline unsigned long bt1_apb_timeout_to_n_us(struct bt1_apb *apb, 818f93662dSSerge Semin unsigned long timeout) 828f93662dSSerge Semin { 838f93662dSSerge Semin u64 n = (u64)timeout * apb->rate; 848f93662dSSerge Semin 858f93662dSSerge Semin do_div(n, USEC_PER_SEC); 868f93662dSSerge Semin 878f93662dSSerge Semin return n; 888f93662dSSerge Semin 898f93662dSSerge Semin } 908f93662dSSerge Semin 918f93662dSSerge Semin static irqreturn_t bt1_apb_isr(int irq, void *data) 928f93662dSSerge Semin { 938f93662dSSerge Semin struct bt1_apb *apb = data; 948f93662dSSerge Semin u32 addr = 0; 958f93662dSSerge Semin 968f93662dSSerge Semin regmap_read(apb->regs, APB_EHB_ADDR, &addr); 978f93662dSSerge Semin 988f93662dSSerge Semin dev_crit_ratelimited(apb->dev, 998f93662dSSerge Semin "APB-bus fault %d: Slave access timeout at 0x%08x\n", 1008f93662dSSerge Semin atomic_inc_return(&apb->count), 1018f93662dSSerge Semin addr); 1028f93662dSSerge Semin 1038f93662dSSerge Semin /* 1048f93662dSSerge Semin * Print backtrace on each CPU. This might be pointless if the fault 1058f93662dSSerge Semin * has happened on the same CPU as the IRQ handler is executed or 1068f93662dSSerge Semin * the other core proceeded further execution despite the error. 1078f93662dSSerge Semin * But if it's not, by looking at the trace we would get straight to 1088f93662dSSerge Semin * the cause of the problem. 1098f93662dSSerge Semin */ 1108f93662dSSerge Semin trigger_all_cpu_backtrace(); 1118f93662dSSerge Semin 1128f93662dSSerge Semin regmap_update_bits(apb->regs, APB_EHB_ISR, APB_EHB_ISR_PENDING, 0); 1138f93662dSSerge Semin 1148f93662dSSerge Semin return IRQ_HANDLED; 1158f93662dSSerge Semin } 1168f93662dSSerge Semin 1178f93662dSSerge Semin static void bt1_apb_clear_data(void *data) 1188f93662dSSerge Semin { 1198f93662dSSerge Semin struct bt1_apb *apb = data; 1208f93662dSSerge Semin struct platform_device *pdev = to_platform_device(apb->dev); 1218f93662dSSerge Semin 1228f93662dSSerge Semin platform_set_drvdata(pdev, NULL); 1238f93662dSSerge Semin } 1248f93662dSSerge Semin 1258f93662dSSerge Semin static struct bt1_apb *bt1_apb_create_data(struct platform_device *pdev) 1268f93662dSSerge Semin { 1278f93662dSSerge Semin struct device *dev = &pdev->dev; 1288f93662dSSerge Semin struct bt1_apb *apb; 1298f93662dSSerge Semin int ret; 1308f93662dSSerge Semin 1318f93662dSSerge Semin apb = devm_kzalloc(dev, sizeof(*apb), GFP_KERNEL); 1328f93662dSSerge Semin if (!apb) 1338f93662dSSerge Semin return ERR_PTR(-ENOMEM); 1348f93662dSSerge Semin 1358f93662dSSerge Semin ret = devm_add_action(dev, bt1_apb_clear_data, apb); 1368f93662dSSerge Semin if (ret) { 1378f93662dSSerge Semin dev_err(dev, "Can't add APB EHB data clear action\n"); 1388f93662dSSerge Semin return ERR_PTR(ret); 1398f93662dSSerge Semin } 1408f93662dSSerge Semin 1418f93662dSSerge Semin apb->dev = dev; 1428f93662dSSerge Semin atomic_set(&apb->count, 0); 1438f93662dSSerge Semin platform_set_drvdata(pdev, apb); 1448f93662dSSerge Semin 1458f93662dSSerge Semin return apb; 1468f93662dSSerge Semin } 1478f93662dSSerge Semin 1488f93662dSSerge Semin static int bt1_apb_request_regs(struct bt1_apb *apb) 1498f93662dSSerge Semin { 1508f93662dSSerge Semin struct platform_device *pdev = to_platform_device(apb->dev); 1518f93662dSSerge Semin void __iomem *regs; 1528f93662dSSerge Semin 1538f93662dSSerge Semin regs = devm_platform_ioremap_resource_byname(pdev, "ehb"); 1548f93662dSSerge Semin if (IS_ERR(regs)) { 1558f93662dSSerge Semin dev_err(apb->dev, "Couldn't map APB EHB registers\n"); 1568f93662dSSerge Semin return PTR_ERR(regs); 1578f93662dSSerge Semin } 1588f93662dSSerge Semin 1598f93662dSSerge Semin apb->regs = devm_regmap_init_mmio(apb->dev, regs, &bt1_apb_regmap_cfg); 1608f93662dSSerge Semin if (IS_ERR(apb->regs)) { 1618f93662dSSerge Semin dev_err(apb->dev, "Couldn't create APB EHB regmap\n"); 1628f93662dSSerge Semin return PTR_ERR(apb->regs); 1638f93662dSSerge Semin } 1648f93662dSSerge Semin 1658f93662dSSerge Semin apb->res = devm_platform_ioremap_resource_byname(pdev, "nodev"); 16675341b3dSSerge Semin if (IS_ERR(apb->res)) 1678f93662dSSerge Semin dev_err(apb->dev, "Couldn't map reserved region\n"); 1688f93662dSSerge Semin 16975341b3dSSerge Semin return PTR_ERR_OR_ZERO(apb->res); 1708f93662dSSerge Semin } 1718f93662dSSerge Semin 1728f93662dSSerge Semin static int bt1_apb_request_rst(struct bt1_apb *apb) 1738f93662dSSerge Semin { 1748f93662dSSerge Semin int ret; 1758f93662dSSerge Semin 1768f93662dSSerge Semin apb->prst = devm_reset_control_get_optional_exclusive(apb->dev, "prst"); 177be5cddefSSerge Semin if (IS_ERR(apb->prst)) 178be5cddefSSerge Semin return dev_err_probe(apb->dev, PTR_ERR(apb->prst), 179be5cddefSSerge Semin "Couldn't get reset control line\n"); 1808f93662dSSerge Semin 1818f93662dSSerge Semin ret = reset_control_deassert(apb->prst); 1828f93662dSSerge Semin if (ret) 1838f93662dSSerge Semin dev_err(apb->dev, "Failed to deassert the reset line\n"); 1848f93662dSSerge Semin 1858f93662dSSerge Semin return ret; 1868f93662dSSerge Semin } 1878f93662dSSerge Semin 1888f93662dSSerge Semin static int bt1_apb_request_clk(struct bt1_apb *apb) 1898f93662dSSerge Semin { 190*6c4cdf4eSWu Bo apb->pclk = devm_clk_get_enabled(apb->dev, "pclk"); 191be5cddefSSerge Semin if (IS_ERR(apb->pclk)) 192be5cddefSSerge Semin return dev_err_probe(apb->dev, PTR_ERR(apb->pclk), 193be5cddefSSerge Semin "Couldn't get APB clock descriptor\n"); 1948f93662dSSerge Semin 1958f93662dSSerge Semin apb->rate = clk_get_rate(apb->pclk); 1968f93662dSSerge Semin if (!apb->rate) { 1978f93662dSSerge Semin dev_err(apb->dev, "Invalid clock rate\n"); 1988f93662dSSerge Semin return -EINVAL; 1998f93662dSSerge Semin } 2008f93662dSSerge Semin 2018f93662dSSerge Semin return 0; 2028f93662dSSerge Semin } 2038f93662dSSerge Semin 2048f93662dSSerge Semin static void bt1_apb_clear_irq(void *data) 2058f93662dSSerge Semin { 2068f93662dSSerge Semin struct bt1_apb *apb = data; 2078f93662dSSerge Semin 2088f93662dSSerge Semin regmap_update_bits(apb->regs, APB_EHB_ISR, APB_EHB_ISR_MASK, 0); 2098f93662dSSerge Semin } 2108f93662dSSerge Semin 2118f93662dSSerge Semin static int bt1_apb_request_irq(struct bt1_apb *apb) 2128f93662dSSerge Semin { 2138f93662dSSerge Semin struct platform_device *pdev = to_platform_device(apb->dev); 2148f93662dSSerge Semin int ret; 2158f93662dSSerge Semin 2168f93662dSSerge Semin apb->irq = platform_get_irq(pdev, 0); 2178f93662dSSerge Semin if (apb->irq < 0) 2188f93662dSSerge Semin return apb->irq; 2198f93662dSSerge Semin 2208f93662dSSerge Semin ret = devm_request_irq(apb->dev, apb->irq, bt1_apb_isr, IRQF_SHARED, 2218f93662dSSerge Semin "bt1-apb", apb); 2228f93662dSSerge Semin if (ret) { 2238f93662dSSerge Semin dev_err(apb->dev, "Couldn't request APB EHB IRQ\n"); 2248f93662dSSerge Semin return ret; 2258f93662dSSerge Semin } 2268f93662dSSerge Semin 2278f93662dSSerge Semin ret = devm_add_action(apb->dev, bt1_apb_clear_irq, apb); 2288f93662dSSerge Semin if (ret) { 2298f93662dSSerge Semin dev_err(apb->dev, "Can't add APB EHB IRQs clear action\n"); 2308f93662dSSerge Semin return ret; 2318f93662dSSerge Semin } 2328f93662dSSerge Semin 2338f93662dSSerge Semin /* Unmask IRQ and clear it' pending flag. */ 2348f93662dSSerge Semin regmap_update_bits(apb->regs, APB_EHB_ISR, 2358f93662dSSerge Semin APB_EHB_ISR_PENDING | APB_EHB_ISR_MASK, 2368f93662dSSerge Semin APB_EHB_ISR_MASK); 2378f93662dSSerge Semin 2388f93662dSSerge Semin return 0; 2398f93662dSSerge Semin } 2408f93662dSSerge Semin 2418f93662dSSerge Semin static ssize_t count_show(struct device *dev, struct device_attribute *attr, 2428f93662dSSerge Semin char *buf) 2438f93662dSSerge Semin { 2448f93662dSSerge Semin struct bt1_apb *apb = dev_get_drvdata(dev); 2458f93662dSSerge Semin 2468f93662dSSerge Semin return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&apb->count)); 2478f93662dSSerge Semin } 2488f93662dSSerge Semin static DEVICE_ATTR_RO(count); 2498f93662dSSerge Semin 2508f93662dSSerge Semin static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, 2518f93662dSSerge Semin char *buf) 2528f93662dSSerge Semin { 2538f93662dSSerge Semin struct bt1_apb *apb = dev_get_drvdata(dev); 2548f93662dSSerge Semin unsigned long timeout; 2558f93662dSSerge Semin int ret; 2568f93662dSSerge Semin u32 n; 2578f93662dSSerge Semin 2588f93662dSSerge Semin ret = regmap_read(apb->regs, APB_EHB_TIMEOUT, &n); 2598f93662dSSerge Semin if (ret) 2608f93662dSSerge Semin return ret; 2618f93662dSSerge Semin 2628f93662dSSerge Semin timeout = bt1_apb_n_to_timeout_us(apb, n); 2638f93662dSSerge Semin 2648f93662dSSerge Semin return scnprintf(buf, PAGE_SIZE, "%lu\n", timeout); 2658f93662dSSerge Semin } 2668f93662dSSerge Semin 2678f93662dSSerge Semin static ssize_t timeout_store(struct device *dev, 2688f93662dSSerge Semin struct device_attribute *attr, 2698f93662dSSerge Semin const char *buf, size_t count) 2708f93662dSSerge Semin { 2718f93662dSSerge Semin struct bt1_apb *apb = dev_get_drvdata(dev); 2728f93662dSSerge Semin unsigned long timeout; 2738f93662dSSerge Semin int ret; 2748f93662dSSerge Semin u32 n; 2758f93662dSSerge Semin 2768f93662dSSerge Semin if (kstrtoul(buf, 0, &timeout) < 0) 2778f93662dSSerge Semin return -EINVAL; 2788f93662dSSerge Semin 2798f93662dSSerge Semin n = bt1_apb_timeout_to_n_us(apb, timeout); 2808f93662dSSerge Semin n = clamp(n, APB_EHB_TIMEOUT_MIN, APB_EHB_TIMEOUT_MAX); 2818f93662dSSerge Semin 2828f93662dSSerge Semin ret = regmap_write(apb->regs, APB_EHB_TIMEOUT, n); 2838f93662dSSerge Semin 2848f93662dSSerge Semin return ret ?: count; 2858f93662dSSerge Semin } 2868f93662dSSerge Semin static DEVICE_ATTR_RW(timeout); 2878f93662dSSerge Semin 288b19dc1b7SSerge Semin static ssize_t inject_error_show(struct device *dev, 289b19dc1b7SSerge Semin struct device_attribute *attr, char *buf) 2908f93662dSSerge Semin { 2918f93662dSSerge Semin return scnprintf(buf, PAGE_SIZE, "Error injection: nodev irq\n"); 2928f93662dSSerge Semin } 2938f93662dSSerge Semin 2948f93662dSSerge Semin static ssize_t inject_error_store(struct device *dev, 2958f93662dSSerge Semin struct device_attribute *attr, 2968f93662dSSerge Semin const char *data, size_t count) 2978f93662dSSerge Semin { 2988f93662dSSerge Semin struct bt1_apb *apb = dev_get_drvdata(dev); 2998f93662dSSerge Semin 3008f93662dSSerge Semin /* 3018f93662dSSerge Semin * Either dummy read from the unmapped address in the APB IO area 3028f93662dSSerge Semin * or manually set the IRQ status. 3038f93662dSSerge Semin */ 304b7cb430dSSerge Semin if (sysfs_streq(data, "nodev")) 3058f93662dSSerge Semin readl(apb->res); 306b7cb430dSSerge Semin else if (sysfs_streq(data, "irq")) 3078f93662dSSerge Semin regmap_update_bits(apb->regs, APB_EHB_ISR, APB_EHB_ISR_PENDING, 3088f93662dSSerge Semin APB_EHB_ISR_PENDING); 3098f93662dSSerge Semin else 3108f93662dSSerge Semin return -EINVAL; 3118f93662dSSerge Semin 3128f93662dSSerge Semin return count; 3138f93662dSSerge Semin } 3148f93662dSSerge Semin static DEVICE_ATTR_RW(inject_error); 3158f93662dSSerge Semin 3168f93662dSSerge Semin static struct attribute *bt1_apb_sysfs_attrs[] = { 3178f93662dSSerge Semin &dev_attr_count.attr, 3188f93662dSSerge Semin &dev_attr_timeout.attr, 3198f93662dSSerge Semin &dev_attr_inject_error.attr, 3208f93662dSSerge Semin NULL 3218f93662dSSerge Semin }; 3228f93662dSSerge Semin ATTRIBUTE_GROUPS(bt1_apb_sysfs); 3238f93662dSSerge Semin 3248f93662dSSerge Semin static void bt1_apb_remove_sysfs(void *data) 3258f93662dSSerge Semin { 3268f93662dSSerge Semin struct bt1_apb *apb = data; 3278f93662dSSerge Semin 3288f93662dSSerge Semin device_remove_groups(apb->dev, bt1_apb_sysfs_groups); 3298f93662dSSerge Semin } 3308f93662dSSerge Semin 3318f93662dSSerge Semin static int bt1_apb_init_sysfs(struct bt1_apb *apb) 3328f93662dSSerge Semin { 3338f93662dSSerge Semin int ret; 3348f93662dSSerge Semin 3358f93662dSSerge Semin ret = device_add_groups(apb->dev, bt1_apb_sysfs_groups); 3368f93662dSSerge Semin if (ret) { 3378f93662dSSerge Semin dev_err(apb->dev, "Failed to create EHB APB sysfs nodes\n"); 3388f93662dSSerge Semin return ret; 3398f93662dSSerge Semin } 3408f93662dSSerge Semin 3418f93662dSSerge Semin ret = devm_add_action_or_reset(apb->dev, bt1_apb_remove_sysfs, apb); 3428f93662dSSerge Semin if (ret) 3438f93662dSSerge Semin dev_err(apb->dev, "Can't add APB EHB sysfs remove action\n"); 3448f93662dSSerge Semin 3458f93662dSSerge Semin return ret; 3468f93662dSSerge Semin } 3478f93662dSSerge Semin 3488f93662dSSerge Semin static int bt1_apb_probe(struct platform_device *pdev) 3498f93662dSSerge Semin { 3508f93662dSSerge Semin struct bt1_apb *apb; 3518f93662dSSerge Semin int ret; 3528f93662dSSerge Semin 3538f93662dSSerge Semin apb = bt1_apb_create_data(pdev); 3548f93662dSSerge Semin if (IS_ERR(apb)) 3558f93662dSSerge Semin return PTR_ERR(apb); 3568f93662dSSerge Semin 3578f93662dSSerge Semin ret = bt1_apb_request_regs(apb); 3588f93662dSSerge Semin if (ret) 3598f93662dSSerge Semin return ret; 3608f93662dSSerge Semin 3618f93662dSSerge Semin ret = bt1_apb_request_rst(apb); 3628f93662dSSerge Semin if (ret) 3638f93662dSSerge Semin return ret; 3648f93662dSSerge Semin 3658f93662dSSerge Semin ret = bt1_apb_request_clk(apb); 3668f93662dSSerge Semin if (ret) 3678f93662dSSerge Semin return ret; 3688f93662dSSerge Semin 3698f93662dSSerge Semin ret = bt1_apb_request_irq(apb); 3708f93662dSSerge Semin if (ret) 3718f93662dSSerge Semin return ret; 3728f93662dSSerge Semin 3738f93662dSSerge Semin ret = bt1_apb_init_sysfs(apb); 3748f93662dSSerge Semin if (ret) 3758f93662dSSerge Semin return ret; 3768f93662dSSerge Semin 3778f93662dSSerge Semin return 0; 3788f93662dSSerge Semin } 3798f93662dSSerge Semin 3808f93662dSSerge Semin static const struct of_device_id bt1_apb_of_match[] = { 3818f93662dSSerge Semin { .compatible = "baikal,bt1-apb" }, 3828f93662dSSerge Semin { } 3838f93662dSSerge Semin }; 3848f93662dSSerge Semin MODULE_DEVICE_TABLE(of, bt1_apb_of_match); 3858f93662dSSerge Semin 3868f93662dSSerge Semin static struct platform_driver bt1_apb_driver = { 3878f93662dSSerge Semin .probe = bt1_apb_probe, 3888f93662dSSerge Semin .driver = { 3898f93662dSSerge Semin .name = "bt1-apb", 3908f93662dSSerge Semin .of_match_table = bt1_apb_of_match 3918f93662dSSerge Semin } 3928f93662dSSerge Semin }; 3938f93662dSSerge Semin module_platform_driver(bt1_apb_driver); 3948f93662dSSerge Semin 3958f93662dSSerge Semin MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>"); 3968f93662dSSerge Semin MODULE_DESCRIPTION("Baikal-T1 APB-bus driver"); 397