1*63cb7713SSerge Semin // SPDX-License-Identifier: GPL-2.0-only 2*63cb7713SSerge Semin /* 3*63cb7713SSerge Semin * Copyright (C) 2020 BAIKAL ELECTRONICS, JSC 4*63cb7713SSerge Semin * 5*63cb7713SSerge Semin * Authors: 6*63cb7713SSerge Semin * Serge Semin <Sergey.Semin@baikalelectronics.ru> 7*63cb7713SSerge Semin * 8*63cb7713SSerge Semin * Baikal-T1 AXI-bus driver 9*63cb7713SSerge Semin */ 10*63cb7713SSerge Semin 11*63cb7713SSerge Semin #include <linux/kernel.h> 12*63cb7713SSerge Semin #include <linux/module.h> 13*63cb7713SSerge Semin #include <linux/types.h> 14*63cb7713SSerge Semin #include <linux/bitfield.h> 15*63cb7713SSerge Semin #include <linux/device.h> 16*63cb7713SSerge Semin #include <linux/atomic.h> 17*63cb7713SSerge Semin #include <linux/regmap.h> 18*63cb7713SSerge Semin #include <linux/platform_device.h> 19*63cb7713SSerge Semin #include <linux/mfd/syscon.h> 20*63cb7713SSerge Semin #include <linux/interrupt.h> 21*63cb7713SSerge Semin #include <linux/io.h> 22*63cb7713SSerge Semin #include <linux/nmi.h> 23*63cb7713SSerge Semin #include <linux/of.h> 24*63cb7713SSerge Semin #include <linux/clk.h> 25*63cb7713SSerge Semin #include <linux/reset.h> 26*63cb7713SSerge Semin #include <linux/sysfs.h> 27*63cb7713SSerge Semin 28*63cb7713SSerge Semin #define BT1_AXI_WERRL 0x110 29*63cb7713SSerge Semin #define BT1_AXI_WERRH 0x114 30*63cb7713SSerge Semin #define BT1_AXI_WERRH_TYPE BIT(23) 31*63cb7713SSerge Semin #define BT1_AXI_WERRH_ADDR_FLD 24 32*63cb7713SSerge Semin #define BT1_AXI_WERRH_ADDR_MASK GENMASK(31, BT1_AXI_WERRH_ADDR_FLD) 33*63cb7713SSerge Semin 34*63cb7713SSerge Semin /* 35*63cb7713SSerge Semin * struct bt1_axi - Baikal-T1 AXI-bus private data 36*63cb7713SSerge Semin * @dev: Pointer to the device structure. 37*63cb7713SSerge Semin * @qos_regs: AXI Interconnect QoS tuning registers. 38*63cb7713SSerge Semin * @sys_regs: Baikal-T1 System Controller registers map. 39*63cb7713SSerge Semin * @irq: Errors IRQ number. 40*63cb7713SSerge Semin * @aclk: AXI reference clock. 41*63cb7713SSerge Semin * @arst: AXI Interconnect reset line. 42*63cb7713SSerge Semin * @count: Number of errors detected. 43*63cb7713SSerge Semin */ 44*63cb7713SSerge Semin struct bt1_axi { 45*63cb7713SSerge Semin struct device *dev; 46*63cb7713SSerge Semin 47*63cb7713SSerge Semin void __iomem *qos_regs; 48*63cb7713SSerge Semin struct regmap *sys_regs; 49*63cb7713SSerge Semin int irq; 50*63cb7713SSerge Semin 51*63cb7713SSerge Semin struct clk *aclk; 52*63cb7713SSerge Semin 53*63cb7713SSerge Semin struct reset_control *arst; 54*63cb7713SSerge Semin 55*63cb7713SSerge Semin atomic_t count; 56*63cb7713SSerge Semin }; 57*63cb7713SSerge Semin 58*63cb7713SSerge Semin static irqreturn_t bt1_axi_isr(int irq, void *data) 59*63cb7713SSerge Semin { 60*63cb7713SSerge Semin struct bt1_axi *axi = data; 61*63cb7713SSerge Semin u32 low = 0, high = 0; 62*63cb7713SSerge Semin 63*63cb7713SSerge Semin regmap_read(axi->sys_regs, BT1_AXI_WERRL, &low); 64*63cb7713SSerge Semin regmap_read(axi->sys_regs, BT1_AXI_WERRH, &high); 65*63cb7713SSerge Semin 66*63cb7713SSerge Semin dev_crit_ratelimited(axi->dev, 67*63cb7713SSerge Semin "AXI-bus fault %d: %s at 0x%x%08x\n", 68*63cb7713SSerge Semin atomic_inc_return(&axi->count), 69*63cb7713SSerge Semin high & BT1_AXI_WERRH_TYPE ? "no slave" : "slave protocol error", 70*63cb7713SSerge Semin high, low); 71*63cb7713SSerge Semin 72*63cb7713SSerge Semin /* 73*63cb7713SSerge Semin * Print backtrace on each CPU. This might be pointless if the fault 74*63cb7713SSerge Semin * has happened on the same CPU as the IRQ handler is executed or 75*63cb7713SSerge Semin * the other core proceeded further execution despite the error. 76*63cb7713SSerge Semin * But if it's not, by looking at the trace we would get straight to 77*63cb7713SSerge Semin * the cause of the problem. 78*63cb7713SSerge Semin */ 79*63cb7713SSerge Semin trigger_all_cpu_backtrace(); 80*63cb7713SSerge Semin 81*63cb7713SSerge Semin return IRQ_HANDLED; 82*63cb7713SSerge Semin } 83*63cb7713SSerge Semin 84*63cb7713SSerge Semin static void bt1_axi_clear_data(void *data) 85*63cb7713SSerge Semin { 86*63cb7713SSerge Semin struct bt1_axi *axi = data; 87*63cb7713SSerge Semin struct platform_device *pdev = to_platform_device(axi->dev); 88*63cb7713SSerge Semin 89*63cb7713SSerge Semin platform_set_drvdata(pdev, NULL); 90*63cb7713SSerge Semin } 91*63cb7713SSerge Semin 92*63cb7713SSerge Semin static struct bt1_axi *bt1_axi_create_data(struct platform_device *pdev) 93*63cb7713SSerge Semin { 94*63cb7713SSerge Semin struct device *dev = &pdev->dev; 95*63cb7713SSerge Semin struct bt1_axi *axi; 96*63cb7713SSerge Semin int ret; 97*63cb7713SSerge Semin 98*63cb7713SSerge Semin axi = devm_kzalloc(dev, sizeof(*axi), GFP_KERNEL); 99*63cb7713SSerge Semin if (!axi) 100*63cb7713SSerge Semin return ERR_PTR(-ENOMEM); 101*63cb7713SSerge Semin 102*63cb7713SSerge Semin ret = devm_add_action(dev, bt1_axi_clear_data, axi); 103*63cb7713SSerge Semin if (ret) { 104*63cb7713SSerge Semin dev_err(dev, "Can't add AXI EHB data clear action\n"); 105*63cb7713SSerge Semin return ERR_PTR(ret); 106*63cb7713SSerge Semin } 107*63cb7713SSerge Semin 108*63cb7713SSerge Semin axi->dev = dev; 109*63cb7713SSerge Semin atomic_set(&axi->count, 0); 110*63cb7713SSerge Semin platform_set_drvdata(pdev, axi); 111*63cb7713SSerge Semin 112*63cb7713SSerge Semin return axi; 113*63cb7713SSerge Semin } 114*63cb7713SSerge Semin 115*63cb7713SSerge Semin static int bt1_axi_request_regs(struct bt1_axi *axi) 116*63cb7713SSerge Semin { 117*63cb7713SSerge Semin struct platform_device *pdev = to_platform_device(axi->dev); 118*63cb7713SSerge Semin struct device *dev = axi->dev; 119*63cb7713SSerge Semin 120*63cb7713SSerge Semin axi->sys_regs = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon"); 121*63cb7713SSerge Semin if (IS_ERR(axi->sys_regs)) { 122*63cb7713SSerge Semin dev_err(dev, "Couldn't find syscon registers\n"); 123*63cb7713SSerge Semin return PTR_ERR(axi->sys_regs); 124*63cb7713SSerge Semin } 125*63cb7713SSerge Semin 126*63cb7713SSerge Semin axi->qos_regs = devm_platform_ioremap_resource_byname(pdev, "qos"); 127*63cb7713SSerge Semin if (IS_ERR(axi->qos_regs)) { 128*63cb7713SSerge Semin dev_err(dev, "Couldn't map AXI-bus QoS registers\n"); 129*63cb7713SSerge Semin return PTR_ERR(axi->qos_regs); 130*63cb7713SSerge Semin } 131*63cb7713SSerge Semin 132*63cb7713SSerge Semin return 0; 133*63cb7713SSerge Semin } 134*63cb7713SSerge Semin 135*63cb7713SSerge Semin static int bt1_axi_request_rst(struct bt1_axi *axi) 136*63cb7713SSerge Semin { 137*63cb7713SSerge Semin int ret; 138*63cb7713SSerge Semin 139*63cb7713SSerge Semin axi->arst = devm_reset_control_get_optional_exclusive(axi->dev, "arst"); 140*63cb7713SSerge Semin if (IS_ERR(axi->arst)) { 141*63cb7713SSerge Semin dev_warn(axi->dev, "Couldn't get reset control line\n"); 142*63cb7713SSerge Semin return PTR_ERR(axi->arst); 143*63cb7713SSerge Semin } 144*63cb7713SSerge Semin 145*63cb7713SSerge Semin ret = reset_control_deassert(axi->arst); 146*63cb7713SSerge Semin if (ret) 147*63cb7713SSerge Semin dev_err(axi->dev, "Failed to deassert the reset line\n"); 148*63cb7713SSerge Semin 149*63cb7713SSerge Semin return ret; 150*63cb7713SSerge Semin } 151*63cb7713SSerge Semin 152*63cb7713SSerge Semin static void bt1_axi_disable_clk(void *data) 153*63cb7713SSerge Semin { 154*63cb7713SSerge Semin struct bt1_axi *axi = data; 155*63cb7713SSerge Semin 156*63cb7713SSerge Semin clk_disable_unprepare(axi->aclk); 157*63cb7713SSerge Semin } 158*63cb7713SSerge Semin 159*63cb7713SSerge Semin static int bt1_axi_request_clk(struct bt1_axi *axi) 160*63cb7713SSerge Semin { 161*63cb7713SSerge Semin int ret; 162*63cb7713SSerge Semin 163*63cb7713SSerge Semin axi->aclk = devm_clk_get(axi->dev, "aclk"); 164*63cb7713SSerge Semin if (IS_ERR(axi->aclk)) { 165*63cb7713SSerge Semin dev_err(axi->dev, "Couldn't get AXI Interconnect clock\n"); 166*63cb7713SSerge Semin return PTR_ERR(axi->aclk); 167*63cb7713SSerge Semin } 168*63cb7713SSerge Semin 169*63cb7713SSerge Semin ret = clk_prepare_enable(axi->aclk); 170*63cb7713SSerge Semin if (ret) { 171*63cb7713SSerge Semin dev_err(axi->dev, "Couldn't enable the AXI clock\n"); 172*63cb7713SSerge Semin return ret; 173*63cb7713SSerge Semin } 174*63cb7713SSerge Semin 175*63cb7713SSerge Semin ret = devm_add_action_or_reset(axi->dev, bt1_axi_disable_clk, axi); 176*63cb7713SSerge Semin if (ret) { 177*63cb7713SSerge Semin dev_err(axi->dev, "Can't add AXI clock disable action\n"); 178*63cb7713SSerge Semin return ret; 179*63cb7713SSerge Semin } 180*63cb7713SSerge Semin 181*63cb7713SSerge Semin return 0; 182*63cb7713SSerge Semin } 183*63cb7713SSerge Semin 184*63cb7713SSerge Semin static int bt1_axi_request_irq(struct bt1_axi *axi) 185*63cb7713SSerge Semin { 186*63cb7713SSerge Semin struct platform_device *pdev = to_platform_device(axi->dev); 187*63cb7713SSerge Semin int ret; 188*63cb7713SSerge Semin 189*63cb7713SSerge Semin axi->irq = platform_get_irq(pdev, 0); 190*63cb7713SSerge Semin if (axi->irq < 0) 191*63cb7713SSerge Semin return axi->irq; 192*63cb7713SSerge Semin 193*63cb7713SSerge Semin ret = devm_request_irq(axi->dev, axi->irq, bt1_axi_isr, IRQF_SHARED, 194*63cb7713SSerge Semin "bt1-axi", axi); 195*63cb7713SSerge Semin if (ret) { 196*63cb7713SSerge Semin dev_err(axi->dev, "Couldn't request AXI EHB IRQ\n"); 197*63cb7713SSerge Semin return ret; 198*63cb7713SSerge Semin } 199*63cb7713SSerge Semin 200*63cb7713SSerge Semin return 0; 201*63cb7713SSerge Semin } 202*63cb7713SSerge Semin 203*63cb7713SSerge Semin static ssize_t count_show(struct device *dev, 204*63cb7713SSerge Semin struct device_attribute *attr, char *buf) 205*63cb7713SSerge Semin { 206*63cb7713SSerge Semin struct bt1_axi *axi = dev_get_drvdata(dev); 207*63cb7713SSerge Semin 208*63cb7713SSerge Semin return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&axi->count)); 209*63cb7713SSerge Semin } 210*63cb7713SSerge Semin static DEVICE_ATTR_RO(count); 211*63cb7713SSerge Semin 212*63cb7713SSerge Semin static ssize_t inject_error_show(struct device *dev, 213*63cb7713SSerge Semin struct device_attribute *attr, char *buf) 214*63cb7713SSerge Semin { 215*63cb7713SSerge Semin return scnprintf(buf, PAGE_SIZE, "Error injection: bus unaligned\n"); 216*63cb7713SSerge Semin } 217*63cb7713SSerge Semin 218*63cb7713SSerge Semin static ssize_t inject_error_store(struct device *dev, 219*63cb7713SSerge Semin struct device_attribute *attr, 220*63cb7713SSerge Semin const char *data, size_t count) 221*63cb7713SSerge Semin { 222*63cb7713SSerge Semin struct bt1_axi *axi = dev_get_drvdata(dev); 223*63cb7713SSerge Semin 224*63cb7713SSerge Semin /* 225*63cb7713SSerge Semin * Performing unaligned read from the memory will cause the CM2 bus 226*63cb7713SSerge Semin * error while unaligned writing - the AXI bus write error handled 227*63cb7713SSerge Semin * by this driver. 228*63cb7713SSerge Semin */ 229*63cb7713SSerge Semin if (!strncmp(data, "bus", 3)) 230*63cb7713SSerge Semin readb(axi->qos_regs); 231*63cb7713SSerge Semin else if (!strncmp(data, "unaligned", 9)) 232*63cb7713SSerge Semin writeb(0, axi->qos_regs); 233*63cb7713SSerge Semin else 234*63cb7713SSerge Semin return -EINVAL; 235*63cb7713SSerge Semin 236*63cb7713SSerge Semin return count; 237*63cb7713SSerge Semin } 238*63cb7713SSerge Semin static DEVICE_ATTR_RW(inject_error); 239*63cb7713SSerge Semin 240*63cb7713SSerge Semin static struct attribute *bt1_axi_sysfs_attrs[] = { 241*63cb7713SSerge Semin &dev_attr_count.attr, 242*63cb7713SSerge Semin &dev_attr_inject_error.attr, 243*63cb7713SSerge Semin NULL 244*63cb7713SSerge Semin }; 245*63cb7713SSerge Semin ATTRIBUTE_GROUPS(bt1_axi_sysfs); 246*63cb7713SSerge Semin 247*63cb7713SSerge Semin static void bt1_axi_remove_sysfs(void *data) 248*63cb7713SSerge Semin { 249*63cb7713SSerge Semin struct bt1_axi *axi = data; 250*63cb7713SSerge Semin 251*63cb7713SSerge Semin device_remove_groups(axi->dev, bt1_axi_sysfs_groups); 252*63cb7713SSerge Semin } 253*63cb7713SSerge Semin 254*63cb7713SSerge Semin static int bt1_axi_init_sysfs(struct bt1_axi *axi) 255*63cb7713SSerge Semin { 256*63cb7713SSerge Semin int ret; 257*63cb7713SSerge Semin 258*63cb7713SSerge Semin ret = device_add_groups(axi->dev, bt1_axi_sysfs_groups); 259*63cb7713SSerge Semin if (ret) { 260*63cb7713SSerge Semin dev_err(axi->dev, "Failed to add sysfs files group\n"); 261*63cb7713SSerge Semin return ret; 262*63cb7713SSerge Semin } 263*63cb7713SSerge Semin 264*63cb7713SSerge Semin ret = devm_add_action_or_reset(axi->dev, bt1_axi_remove_sysfs, axi); 265*63cb7713SSerge Semin if (ret) 266*63cb7713SSerge Semin dev_err(axi->dev, "Can't add AXI EHB sysfs remove action\n"); 267*63cb7713SSerge Semin 268*63cb7713SSerge Semin return ret; 269*63cb7713SSerge Semin } 270*63cb7713SSerge Semin 271*63cb7713SSerge Semin static int bt1_axi_probe(struct platform_device *pdev) 272*63cb7713SSerge Semin { 273*63cb7713SSerge Semin struct bt1_axi *axi; 274*63cb7713SSerge Semin int ret; 275*63cb7713SSerge Semin 276*63cb7713SSerge Semin axi = bt1_axi_create_data(pdev); 277*63cb7713SSerge Semin if (IS_ERR(axi)) 278*63cb7713SSerge Semin return PTR_ERR(axi); 279*63cb7713SSerge Semin 280*63cb7713SSerge Semin ret = bt1_axi_request_regs(axi); 281*63cb7713SSerge Semin if (ret) 282*63cb7713SSerge Semin return ret; 283*63cb7713SSerge Semin 284*63cb7713SSerge Semin ret = bt1_axi_request_rst(axi); 285*63cb7713SSerge Semin if (ret) 286*63cb7713SSerge Semin return ret; 287*63cb7713SSerge Semin 288*63cb7713SSerge Semin ret = bt1_axi_request_clk(axi); 289*63cb7713SSerge Semin if (ret) 290*63cb7713SSerge Semin return ret; 291*63cb7713SSerge Semin 292*63cb7713SSerge Semin ret = bt1_axi_request_irq(axi); 293*63cb7713SSerge Semin if (ret) 294*63cb7713SSerge Semin return ret; 295*63cb7713SSerge Semin 296*63cb7713SSerge Semin ret = bt1_axi_init_sysfs(axi); 297*63cb7713SSerge Semin if (ret) 298*63cb7713SSerge Semin return ret; 299*63cb7713SSerge Semin 300*63cb7713SSerge Semin return 0; 301*63cb7713SSerge Semin } 302*63cb7713SSerge Semin 303*63cb7713SSerge Semin static const struct of_device_id bt1_axi_of_match[] = { 304*63cb7713SSerge Semin { .compatible = "baikal,bt1-axi" }, 305*63cb7713SSerge Semin { } 306*63cb7713SSerge Semin }; 307*63cb7713SSerge Semin MODULE_DEVICE_TABLE(of, bt1_axi_of_match); 308*63cb7713SSerge Semin 309*63cb7713SSerge Semin static struct platform_driver bt1_axi_driver = { 310*63cb7713SSerge Semin .probe = bt1_axi_probe, 311*63cb7713SSerge Semin .driver = { 312*63cb7713SSerge Semin .name = "bt1-axi", 313*63cb7713SSerge Semin .of_match_table = bt1_axi_of_match 314*63cb7713SSerge Semin } 315*63cb7713SSerge Semin }; 316*63cb7713SSerge Semin module_platform_driver(bt1_axi_driver); 317*63cb7713SSerge Semin 318*63cb7713SSerge Semin MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>"); 319*63cb7713SSerge Semin MODULE_DESCRIPTION("Baikal-T1 AXI-bus driver"); 320*63cb7713SSerge Semin MODULE_LICENSE("GPL v2"); 321