163cb7713SSerge Semin // SPDX-License-Identifier: GPL-2.0-only 263cb7713SSerge Semin /* 363cb7713SSerge Semin * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC 463cb7713SSerge Semin * 563cb7713SSerge Semin * Authors: 663cb7713SSerge Semin * Serge Semin <Sergey.Semin@baikalelectronics.ru> 763cb7713SSerge Semin * 863cb7713SSerge Semin * Baikal-T1 AXI-bus driver 963cb7713SSerge Semin */ 1063cb7713SSerge Semin 1163cb7713SSerge Semin #include <linux/kernel.h> 1263cb7713SSerge Semin #include <linux/module.h> 1363cb7713SSerge Semin #include <linux/types.h> 1463cb7713SSerge Semin #include <linux/bitfield.h> 1563cb7713SSerge Semin #include <linux/device.h> 1663cb7713SSerge Semin #include <linux/atomic.h> 1763cb7713SSerge Semin #include <linux/regmap.h> 1863cb7713SSerge Semin #include <linux/platform_device.h> 1963cb7713SSerge Semin #include <linux/mfd/syscon.h> 2063cb7713SSerge Semin #include <linux/interrupt.h> 2163cb7713SSerge Semin #include <linux/io.h> 2263cb7713SSerge Semin #include <linux/nmi.h> 2363cb7713SSerge Semin #include <linux/of.h> 2463cb7713SSerge Semin #include <linux/clk.h> 2563cb7713SSerge Semin #include <linux/reset.h> 2663cb7713SSerge Semin #include <linux/sysfs.h> 2763cb7713SSerge Semin 2863cb7713SSerge Semin #define BT1_AXI_WERRL 0x110 2963cb7713SSerge Semin #define BT1_AXI_WERRH 0x114 3063cb7713SSerge Semin #define BT1_AXI_WERRH_TYPE BIT(23) 3163cb7713SSerge Semin #define BT1_AXI_WERRH_ADDR_FLD 24 3263cb7713SSerge Semin #define BT1_AXI_WERRH_ADDR_MASK GENMASK(31, BT1_AXI_WERRH_ADDR_FLD) 3363cb7713SSerge Semin 3463cb7713SSerge Semin /* 3563cb7713SSerge Semin * struct bt1_axi - Baikal-T1 AXI-bus private data 3663cb7713SSerge Semin * @dev: Pointer to the device structure. 3763cb7713SSerge Semin * @qos_regs: AXI Interconnect QoS tuning registers. 3863cb7713SSerge Semin * @sys_regs: Baikal-T1 System Controller registers map. 3963cb7713SSerge Semin * @irq: Errors IRQ number. 4063cb7713SSerge Semin * @aclk: AXI reference clock. 4163cb7713SSerge Semin * @arst: AXI Interconnect reset line. 4263cb7713SSerge Semin * @count: Number of errors detected. 4363cb7713SSerge Semin */ 4463cb7713SSerge Semin struct bt1_axi { 4563cb7713SSerge Semin struct device *dev; 4663cb7713SSerge Semin 4763cb7713SSerge Semin void __iomem *qos_regs; 4863cb7713SSerge Semin struct regmap *sys_regs; 4963cb7713SSerge Semin int irq; 5063cb7713SSerge Semin 5163cb7713SSerge Semin struct clk *aclk; 5263cb7713SSerge Semin 5363cb7713SSerge Semin struct reset_control *arst; 5463cb7713SSerge Semin 5563cb7713SSerge Semin atomic_t count; 5663cb7713SSerge Semin }; 5763cb7713SSerge Semin 5863cb7713SSerge Semin static irqreturn_t bt1_axi_isr(int irq, void *data) 5963cb7713SSerge Semin { 6063cb7713SSerge Semin struct bt1_axi *axi = data; 6163cb7713SSerge Semin u32 low = 0, high = 0; 6263cb7713SSerge Semin 6363cb7713SSerge Semin regmap_read(axi->sys_regs, BT1_AXI_WERRL, &low); 6463cb7713SSerge Semin regmap_read(axi->sys_regs, BT1_AXI_WERRH, &high); 6563cb7713SSerge Semin 6663cb7713SSerge Semin dev_crit_ratelimited(axi->dev, 6763cb7713SSerge Semin "AXI-bus fault %d: %s at 0x%x%08x\n", 6863cb7713SSerge Semin atomic_inc_return(&axi->count), 6963cb7713SSerge Semin high & BT1_AXI_WERRH_TYPE ? "no slave" : "slave protocol error", 7063cb7713SSerge Semin high, low); 7163cb7713SSerge Semin 7263cb7713SSerge Semin /* 7363cb7713SSerge Semin * Print backtrace on each CPU. This might be pointless if the fault 7463cb7713SSerge Semin * has happened on the same CPU as the IRQ handler is executed or 7563cb7713SSerge Semin * the other core proceeded further execution despite the error. 7663cb7713SSerge Semin * But if it's not, by looking at the trace we would get straight to 7763cb7713SSerge Semin * the cause of the problem. 7863cb7713SSerge Semin */ 7963cb7713SSerge Semin trigger_all_cpu_backtrace(); 8063cb7713SSerge Semin 8163cb7713SSerge Semin return IRQ_HANDLED; 8263cb7713SSerge Semin } 8363cb7713SSerge Semin 8463cb7713SSerge Semin static void bt1_axi_clear_data(void *data) 8563cb7713SSerge Semin { 8663cb7713SSerge Semin struct bt1_axi *axi = data; 8763cb7713SSerge Semin struct platform_device *pdev = to_platform_device(axi->dev); 8863cb7713SSerge Semin 8963cb7713SSerge Semin platform_set_drvdata(pdev, NULL); 9063cb7713SSerge Semin } 9163cb7713SSerge Semin 9263cb7713SSerge Semin static struct bt1_axi *bt1_axi_create_data(struct platform_device *pdev) 9363cb7713SSerge Semin { 9463cb7713SSerge Semin struct device *dev = &pdev->dev; 9563cb7713SSerge Semin struct bt1_axi *axi; 9663cb7713SSerge Semin int ret; 9763cb7713SSerge Semin 9863cb7713SSerge Semin axi = devm_kzalloc(dev, sizeof(*axi), GFP_KERNEL); 9963cb7713SSerge Semin if (!axi) 10063cb7713SSerge Semin return ERR_PTR(-ENOMEM); 10163cb7713SSerge Semin 10263cb7713SSerge Semin ret = devm_add_action(dev, bt1_axi_clear_data, axi); 10363cb7713SSerge Semin if (ret) { 10463cb7713SSerge Semin dev_err(dev, "Can't add AXI EHB data clear action\n"); 10563cb7713SSerge Semin return ERR_PTR(ret); 10663cb7713SSerge Semin } 10763cb7713SSerge Semin 10863cb7713SSerge Semin axi->dev = dev; 10963cb7713SSerge Semin atomic_set(&axi->count, 0); 11063cb7713SSerge Semin platform_set_drvdata(pdev, axi); 11163cb7713SSerge Semin 11263cb7713SSerge Semin return axi; 11363cb7713SSerge Semin } 11463cb7713SSerge Semin 11563cb7713SSerge Semin static int bt1_axi_request_regs(struct bt1_axi *axi) 11663cb7713SSerge Semin { 11763cb7713SSerge Semin struct platform_device *pdev = to_platform_device(axi->dev); 11863cb7713SSerge Semin struct device *dev = axi->dev; 11963cb7713SSerge Semin 12063cb7713SSerge Semin axi->sys_regs = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); 12163cb7713SSerge Semin if (IS_ERR(axi->sys_regs)) { 12263cb7713SSerge Semin dev_err(dev, "Couldn't find syscon registers\n"); 12363cb7713SSerge Semin return PTR_ERR(axi->sys_regs); 12463cb7713SSerge Semin } 12563cb7713SSerge Semin 12663cb7713SSerge Semin axi->qos_regs = devm_platform_ioremap_resource_byname(pdev, "qos"); 1277f57416fSSerge Semin if (IS_ERR(axi->qos_regs)) 12863cb7713SSerge Semin dev_err(dev, "Couldn't map AXI-bus QoS registers\n"); 12963cb7713SSerge Semin 1307f57416fSSerge Semin return PTR_ERR_OR_ZERO(axi->qos_regs); 13163cb7713SSerge Semin } 13263cb7713SSerge Semin 13363cb7713SSerge Semin static int bt1_axi_request_rst(struct bt1_axi *axi) 13463cb7713SSerge Semin { 13563cb7713SSerge Semin int ret; 13663cb7713SSerge Semin 13763cb7713SSerge Semin axi->arst = devm_reset_control_get_optional_exclusive(axi->dev, "arst"); 138*5e93207eSSerge Semin if (IS_ERR(axi->arst)) 139*5e93207eSSerge Semin return dev_err_probe(axi->dev, PTR_ERR(axi->arst), 140*5e93207eSSerge Semin "Couldn't get reset control line\n"); 14163cb7713SSerge Semin 14263cb7713SSerge Semin ret = reset_control_deassert(axi->arst); 14363cb7713SSerge Semin if (ret) 14463cb7713SSerge Semin dev_err(axi->dev, "Failed to deassert the reset line\n"); 14563cb7713SSerge Semin 14663cb7713SSerge Semin return ret; 14763cb7713SSerge Semin } 14863cb7713SSerge Semin 14963cb7713SSerge Semin static void bt1_axi_disable_clk(void *data) 15063cb7713SSerge Semin { 15163cb7713SSerge Semin struct bt1_axi *axi = data; 15263cb7713SSerge Semin 15363cb7713SSerge Semin clk_disable_unprepare(axi->aclk); 15463cb7713SSerge Semin } 15563cb7713SSerge Semin 15663cb7713SSerge Semin static int bt1_axi_request_clk(struct bt1_axi *axi) 15763cb7713SSerge Semin { 15863cb7713SSerge Semin int ret; 15963cb7713SSerge Semin 16063cb7713SSerge Semin axi->aclk = devm_clk_get(axi->dev, "aclk"); 161*5e93207eSSerge Semin if (IS_ERR(axi->aclk)) 162*5e93207eSSerge Semin return dev_err_probe(axi->dev, PTR_ERR(axi->aclk), 163*5e93207eSSerge Semin "Couldn't get AXI Interconnect clock\n"); 16463cb7713SSerge Semin 16563cb7713SSerge Semin ret = clk_prepare_enable(axi->aclk); 16663cb7713SSerge Semin if (ret) { 16763cb7713SSerge Semin dev_err(axi->dev, "Couldn't enable the AXI clock\n"); 16863cb7713SSerge Semin return ret; 16963cb7713SSerge Semin } 17063cb7713SSerge Semin 17163cb7713SSerge Semin ret = devm_add_action_or_reset(axi->dev, bt1_axi_disable_clk, axi); 1727f57416fSSerge Semin if (ret) 17363cb7713SSerge Semin dev_err(axi->dev, "Can't add AXI clock disable action\n"); 17463cb7713SSerge Semin 1757f57416fSSerge Semin return ret; 17663cb7713SSerge Semin } 17763cb7713SSerge Semin 17863cb7713SSerge Semin static int bt1_axi_request_irq(struct bt1_axi *axi) 17963cb7713SSerge Semin { 18063cb7713SSerge Semin struct platform_device *pdev = to_platform_device(axi->dev); 18163cb7713SSerge Semin int ret; 18263cb7713SSerge Semin 18363cb7713SSerge Semin axi->irq = platform_get_irq(pdev, 0); 18463cb7713SSerge Semin if (axi->irq < 0) 18563cb7713SSerge Semin return axi->irq; 18663cb7713SSerge Semin 18763cb7713SSerge Semin ret = devm_request_irq(axi->dev, axi->irq, bt1_axi_isr, IRQF_SHARED, 18863cb7713SSerge Semin "bt1-axi", axi); 1897f57416fSSerge Semin if (ret) 19063cb7713SSerge Semin dev_err(axi->dev, "Couldn't request AXI EHB IRQ\n"); 19163cb7713SSerge Semin 1927f57416fSSerge Semin return ret; 19363cb7713SSerge Semin } 19463cb7713SSerge Semin 19563cb7713SSerge Semin static ssize_t count_show(struct device *dev, 19663cb7713SSerge Semin struct device_attribute *attr, char *buf) 19763cb7713SSerge Semin { 19863cb7713SSerge Semin struct bt1_axi *axi = dev_get_drvdata(dev); 19963cb7713SSerge Semin 20063cb7713SSerge Semin return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&axi->count)); 20163cb7713SSerge Semin } 20263cb7713SSerge Semin static DEVICE_ATTR_RO(count); 20363cb7713SSerge Semin 20463cb7713SSerge Semin static ssize_t inject_error_show(struct device *dev, 20563cb7713SSerge Semin struct device_attribute *attr, char *buf) 20663cb7713SSerge Semin { 20763cb7713SSerge Semin return scnprintf(buf, PAGE_SIZE, "Error injection: bus unaligned\n"); 20863cb7713SSerge Semin } 20963cb7713SSerge Semin 21063cb7713SSerge Semin static ssize_t inject_error_store(struct device *dev, 21163cb7713SSerge Semin struct device_attribute *attr, 21263cb7713SSerge Semin const char *data, size_t count) 21363cb7713SSerge Semin { 21463cb7713SSerge Semin struct bt1_axi *axi = dev_get_drvdata(dev); 21563cb7713SSerge Semin 21663cb7713SSerge Semin /* 21763cb7713SSerge Semin * Performing unaligned read from the memory will cause the CM2 bus 21863cb7713SSerge Semin * error while unaligned writing - the AXI bus write error handled 21963cb7713SSerge Semin * by this driver. 22063cb7713SSerge Semin */ 22191920088SSerge Semin if (sysfs_streq(data, "bus")) 22263cb7713SSerge Semin readb(axi->qos_regs); 22391920088SSerge Semin else if (sysfs_streq(data, "unaligned")) 22463cb7713SSerge Semin writeb(0, axi->qos_regs); 22563cb7713SSerge Semin else 22663cb7713SSerge Semin return -EINVAL; 22763cb7713SSerge Semin 22863cb7713SSerge Semin return count; 22963cb7713SSerge Semin } 23063cb7713SSerge Semin static DEVICE_ATTR_RW(inject_error); 23163cb7713SSerge Semin 23263cb7713SSerge Semin static struct attribute *bt1_axi_sysfs_attrs[] = { 23363cb7713SSerge Semin &dev_attr_count.attr, 23463cb7713SSerge Semin &dev_attr_inject_error.attr, 23563cb7713SSerge Semin NULL 23663cb7713SSerge Semin }; 23763cb7713SSerge Semin ATTRIBUTE_GROUPS(bt1_axi_sysfs); 23863cb7713SSerge Semin 23963cb7713SSerge Semin static void bt1_axi_remove_sysfs(void *data) 24063cb7713SSerge Semin { 24163cb7713SSerge Semin struct bt1_axi *axi = data; 24263cb7713SSerge Semin 24363cb7713SSerge Semin device_remove_groups(axi->dev, bt1_axi_sysfs_groups); 24463cb7713SSerge Semin } 24563cb7713SSerge Semin 24663cb7713SSerge Semin static int bt1_axi_init_sysfs(struct bt1_axi *axi) 24763cb7713SSerge Semin { 24863cb7713SSerge Semin int ret; 24963cb7713SSerge Semin 25063cb7713SSerge Semin ret = device_add_groups(axi->dev, bt1_axi_sysfs_groups); 25163cb7713SSerge Semin if (ret) { 25263cb7713SSerge Semin dev_err(axi->dev, "Failed to add sysfs files group\n"); 25363cb7713SSerge Semin return ret; 25463cb7713SSerge Semin } 25563cb7713SSerge Semin 25663cb7713SSerge Semin ret = devm_add_action_or_reset(axi->dev, bt1_axi_remove_sysfs, axi); 25763cb7713SSerge Semin if (ret) 25863cb7713SSerge Semin dev_err(axi->dev, "Can't add AXI EHB sysfs remove action\n"); 25963cb7713SSerge Semin 26063cb7713SSerge Semin return ret; 26163cb7713SSerge Semin } 26263cb7713SSerge Semin 26363cb7713SSerge Semin static int bt1_axi_probe(struct platform_device *pdev) 26463cb7713SSerge Semin { 26563cb7713SSerge Semin struct bt1_axi *axi; 26663cb7713SSerge Semin int ret; 26763cb7713SSerge Semin 26863cb7713SSerge Semin axi = bt1_axi_create_data(pdev); 26963cb7713SSerge Semin if (IS_ERR(axi)) 27063cb7713SSerge Semin return PTR_ERR(axi); 27163cb7713SSerge Semin 27263cb7713SSerge Semin ret = bt1_axi_request_regs(axi); 27363cb7713SSerge Semin if (ret) 27463cb7713SSerge Semin return ret; 27563cb7713SSerge Semin 27663cb7713SSerge Semin ret = bt1_axi_request_rst(axi); 27763cb7713SSerge Semin if (ret) 27863cb7713SSerge Semin return ret; 27963cb7713SSerge Semin 28063cb7713SSerge Semin ret = bt1_axi_request_clk(axi); 28163cb7713SSerge Semin if (ret) 28263cb7713SSerge Semin return ret; 28363cb7713SSerge Semin 28463cb7713SSerge Semin ret = bt1_axi_request_irq(axi); 28563cb7713SSerge Semin if (ret) 28663cb7713SSerge Semin return ret; 28763cb7713SSerge Semin 28863cb7713SSerge Semin ret = bt1_axi_init_sysfs(axi); 28963cb7713SSerge Semin if (ret) 29063cb7713SSerge Semin return ret; 29163cb7713SSerge Semin 29263cb7713SSerge Semin return 0; 29363cb7713SSerge Semin } 29463cb7713SSerge Semin 29563cb7713SSerge Semin static const struct of_device_id bt1_axi_of_match[] = { 29663cb7713SSerge Semin { .compatible = "baikal,bt1-axi" }, 29763cb7713SSerge Semin { } 29863cb7713SSerge Semin }; 29963cb7713SSerge Semin MODULE_DEVICE_TABLE(of, bt1_axi_of_match); 30063cb7713SSerge Semin 30163cb7713SSerge Semin static struct platform_driver bt1_axi_driver = { 30263cb7713SSerge Semin .probe = bt1_axi_probe, 30363cb7713SSerge Semin .driver = { 30463cb7713SSerge Semin .name = "bt1-axi", 30563cb7713SSerge Semin .of_match_table = bt1_axi_of_match 30663cb7713SSerge Semin } 30763cb7713SSerge Semin }; 30863cb7713SSerge Semin module_platform_driver(bt1_axi_driver); 30963cb7713SSerge Semin 31063cb7713SSerge Semin MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>"); 31163cb7713SSerge Semin MODULE_DESCRIPTION("Baikal-T1 AXI-bus driver"); 31263cb7713SSerge Semin MODULE_LICENSE("GPL v2"); 313