0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/init.h>
0010 #include <linux/interrupt.h>
0011 #include <linux/io.h>
0012 #include <linux/kernel.h>
0013 #include <linux/module.h>
0014 #include <linux/of_device.h>
0015 #include <linux/of.h>
0016 #include <linux/platform_device.h>
0017 #include <linux/slab.h>
0018
0019 #include "omap_l3_noc.h"
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050 static int l3_handle_target(struct omap_l3 *l3, void __iomem *base,
0051 struct l3_flagmux_data *flag_mux, int err_src)
0052 {
0053 int k;
0054 u32 std_err_main, clear, masterid;
0055 u8 op_code, m_req_info;
0056 void __iomem *l3_targ_base;
0057 void __iomem *l3_targ_stderr, *l3_targ_slvofslsb, *l3_targ_mstaddr;
0058 void __iomem *l3_targ_hdr, *l3_targ_info;
0059 struct l3_target_data *l3_targ_inst;
0060 struct l3_masters_data *master;
0061 char *target_name, *master_name = "UN IDENTIFIED";
0062 char *err_description;
0063 char err_string[30] = { 0 };
0064 char info_string[60] = { 0 };
0065
0066
0067 BUG_ON(err_src > MAX_CLKDM_TARGETS);
0068
0069 if (err_src < flag_mux->num_targ_data) {
0070 l3_targ_inst = &flag_mux->l3_targ[err_src];
0071 target_name = l3_targ_inst->name;
0072 l3_targ_base = base + l3_targ_inst->offset;
0073 } else {
0074 target_name = L3_TARGET_NOT_SUPPORTED;
0075 }
0076
0077 if (target_name == L3_TARGET_NOT_SUPPORTED)
0078 return -ENODEV;
0079
0080
0081 l3_targ_stderr = l3_targ_base + L3_TARG_STDERRLOG_MAIN;
0082 l3_targ_slvofslsb = l3_targ_base + L3_TARG_STDERRLOG_SLVOFSLSB;
0083
0084 std_err_main = readl_relaxed(l3_targ_stderr);
0085
0086 switch (std_err_main & CUSTOM_ERROR) {
0087 case STANDARD_ERROR:
0088 err_description = "Standard";
0089 snprintf(err_string, sizeof(err_string),
0090 ": At Address: 0x%08X ",
0091 readl_relaxed(l3_targ_slvofslsb));
0092
0093 l3_targ_mstaddr = l3_targ_base + L3_TARG_STDERRLOG_MSTADDR;
0094 l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_HDR;
0095 l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_INFO;
0096 break;
0097
0098 case CUSTOM_ERROR:
0099 err_description = "Custom";
0100
0101 l3_targ_mstaddr = l3_targ_base +
0102 L3_TARG_STDERRLOG_CINFO_MSTADDR;
0103 l3_targ_hdr = l3_targ_base + L3_TARG_STDERRLOG_CINFO_OPCODE;
0104 l3_targ_info = l3_targ_base + L3_TARG_STDERRLOG_CINFO_INFO;
0105 break;
0106
0107 default:
0108
0109 return 0;
0110 }
0111
0112
0113 masterid = (readl_relaxed(l3_targ_mstaddr) &
0114 l3->mst_addr_mask) >> __ffs(l3->mst_addr_mask);
0115
0116 for (k = 0, master = l3->l3_masters; k < l3->num_masters;
0117 k++, master++) {
0118 if (masterid == master->id) {
0119 master_name = master->name;
0120 break;
0121 }
0122 }
0123
0124 op_code = readl_relaxed(l3_targ_hdr) & 0x7;
0125
0126 m_req_info = readl_relaxed(l3_targ_info) & 0xF;
0127 snprintf(info_string, sizeof(info_string),
0128 ": %s in %s mode during %s access",
0129 (m_req_info & BIT(0)) ? "Opcode Fetch" : "Data Access",
0130 (m_req_info & BIT(1)) ? "Supervisor" : "User",
0131 (m_req_info & BIT(3)) ? "Debug" : "Functional");
0132
0133 WARN(true,
0134 "%s:L3 %s Error: MASTER %s TARGET %s (%s)%s%s\n",
0135 dev_name(l3->dev),
0136 err_description,
0137 master_name, target_name,
0138 l3_transaction_type[op_code],
0139 err_string, info_string);
0140
0141
0142 clear = std_err_main | CLEAR_STDERR_LOG;
0143 writel_relaxed(clear, l3_targ_stderr);
0144
0145 return 0;
0146 }
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159 static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
0160 {
0161 struct omap_l3 *l3 = _l3;
0162 int inttype, i, ret;
0163 int err_src = 0;
0164 u32 err_reg, mask_val;
0165 void __iomem *base, *mask_reg;
0166 struct l3_flagmux_data *flag_mux;
0167
0168
0169 inttype = irq == l3->app_irq ? L3_APPLICATION_ERROR : L3_DEBUG_ERROR;
0170
0171 for (i = 0; i < l3->num_modules; i++) {
0172
0173
0174
0175
0176 base = l3->l3_base[i];
0177 flag_mux = l3->l3_flagmux[i];
0178 err_reg = readl_relaxed(base + flag_mux->offset +
0179 L3_FLAGMUX_REGERR0 + (inttype << 3));
0180
0181 err_reg &= ~(inttype ? flag_mux->mask_app_bits :
0182 flag_mux->mask_dbg_bits);
0183
0184
0185 if (err_reg) {
0186
0187 err_src = __ffs(err_reg);
0188
0189 ret = l3_handle_target(l3, base, flag_mux, err_src);
0190
0191
0192
0193
0194
0195
0196
0197 if (ret) {
0198 dev_err(l3->dev,
0199 "L3 %s error: target %d mod:%d %s\n",
0200 inttype ? "debug" : "application",
0201 err_src, i, "(unclearable)");
0202
0203 mask_reg = base + flag_mux->offset +
0204 L3_FLAGMUX_MASK0 + (inttype << 3);
0205 mask_val = readl_relaxed(mask_reg);
0206 mask_val &= ~(1 << err_src);
0207 writel_relaxed(mask_val, mask_reg);
0208
0209
0210 if (inttype)
0211 flag_mux->mask_app_bits |= 1 << err_src;
0212 else
0213 flag_mux->mask_dbg_bits |= 1 << err_src;
0214 }
0215
0216
0217 return IRQ_HANDLED;
0218 }
0219 }
0220
0221 dev_err(l3->dev, "L3 %s IRQ not handled!!\n",
0222 inttype ? "debug" : "application");
0223
0224 return IRQ_NONE;
0225 }
0226
0227 static const struct of_device_id l3_noc_match[] = {
0228 {.compatible = "ti,omap4-l3-noc", .data = &omap4_l3_data},
0229 {.compatible = "ti,omap5-l3-noc", .data = &omap5_l3_data},
0230 {.compatible = "ti,dra7-l3-noc", .data = &dra_l3_data},
0231 {.compatible = "ti,am4372-l3-noc", .data = &am4372_l3_data},
0232 {},
0233 };
0234 MODULE_DEVICE_TABLE(of, l3_noc_match);
0235
0236 static int omap_l3_probe(struct platform_device *pdev)
0237 {
0238 const struct of_device_id *of_id;
0239 static struct omap_l3 *l3;
0240 int ret, i, res_idx;
0241
0242 of_id = of_match_device(l3_noc_match, &pdev->dev);
0243 if (!of_id) {
0244 dev_err(&pdev->dev, "OF data missing\n");
0245 return -EINVAL;
0246 }
0247
0248 l3 = devm_kzalloc(&pdev->dev, sizeof(*l3), GFP_KERNEL);
0249 if (!l3)
0250 return -ENOMEM;
0251
0252 memcpy(l3, of_id->data, sizeof(*l3));
0253 l3->dev = &pdev->dev;
0254 platform_set_drvdata(pdev, l3);
0255
0256
0257 for (i = 0, res_idx = 0; i < l3->num_modules; i++) {
0258 struct resource *res;
0259
0260 if (l3->l3_base[i] == L3_BASE_IS_SUBMODULE) {
0261
0262 BUG_ON(i == 0);
0263 l3->l3_base[i] = l3->l3_base[i - 1];
0264 continue;
0265 }
0266 res = platform_get_resource(pdev, IORESOURCE_MEM, res_idx);
0267 l3->l3_base[i] = devm_ioremap_resource(&pdev->dev, res);
0268 if (IS_ERR(l3->l3_base[i])) {
0269 dev_err(l3->dev, "ioremap %d failed\n", i);
0270 return PTR_ERR(l3->l3_base[i]);
0271 }
0272 res_idx++;
0273 }
0274
0275
0276
0277
0278 l3->debug_irq = platform_get_irq(pdev, 0);
0279 ret = devm_request_irq(l3->dev, l3->debug_irq, l3_interrupt_handler,
0280 IRQF_NO_THREAD, "l3-dbg-irq", l3);
0281 if (ret) {
0282 dev_err(l3->dev, "request_irq failed for %d\n",
0283 l3->debug_irq);
0284 return ret;
0285 }
0286
0287 l3->app_irq = platform_get_irq(pdev, 1);
0288 ret = devm_request_irq(l3->dev, l3->app_irq, l3_interrupt_handler,
0289 IRQF_NO_THREAD, "l3-app-irq", l3);
0290 if (ret)
0291 dev_err(l3->dev, "request_irq failed for %d\n", l3->app_irq);
0292
0293 return ret;
0294 }
0295
0296 #ifdef CONFIG_PM_SLEEP
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306 static int l3_resume_noirq(struct device *dev)
0307 {
0308 struct omap_l3 *l3 = dev_get_drvdata(dev);
0309 int i;
0310 struct l3_flagmux_data *flag_mux;
0311 void __iomem *base, *mask_regx = NULL;
0312 u32 mask_val;
0313
0314 for (i = 0; i < l3->num_modules; i++) {
0315 base = l3->l3_base[i];
0316 flag_mux = l3->l3_flagmux[i];
0317 if (!flag_mux->mask_app_bits && !flag_mux->mask_dbg_bits)
0318 continue;
0319
0320 mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
0321 (L3_APPLICATION_ERROR << 3);
0322 mask_val = readl_relaxed(mask_regx);
0323 mask_val &= ~(flag_mux->mask_app_bits);
0324
0325 writel_relaxed(mask_val, mask_regx);
0326 mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
0327 (L3_DEBUG_ERROR << 3);
0328 mask_val = readl_relaxed(mask_regx);
0329 mask_val &= ~(flag_mux->mask_dbg_bits);
0330
0331 writel_relaxed(mask_val, mask_regx);
0332 }
0333
0334
0335 if (mask_regx)
0336 (void)readl(mask_regx);
0337
0338 return 0;
0339 }
0340
0341 static const struct dev_pm_ops l3_dev_pm_ops = {
0342 SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(NULL, l3_resume_noirq)
0343 };
0344
0345 #define L3_DEV_PM_OPS (&l3_dev_pm_ops)
0346 #else
0347 #define L3_DEV_PM_OPS NULL
0348 #endif
0349
0350 static struct platform_driver omap_l3_driver = {
0351 .probe = omap_l3_probe,
0352 .driver = {
0353 .name = "omap_l3_noc",
0354 .pm = L3_DEV_PM_OPS,
0355 .of_match_table = of_match_ptr(l3_noc_match),
0356 },
0357 };
0358
0359 static int __init omap_l3_init(void)
0360 {
0361 return platform_driver_register(&omap_l3_driver);
0362 }
0363 postcore_initcall_sync(omap_l3_init);
0364
0365 static void __exit omap_l3_exit(void)
0366 {
0367 platform_driver_unregister(&omap_l3_driver);
0368 }
0369 module_exit(omap_l3_exit);
0370
0371 MODULE_AUTHOR("Santosh Shilimkar");
0372 MODULE_AUTHOR("Sricharan R");
0373 MODULE_DESCRIPTION("OMAP L3 Interconnect error handling driver");
0374 MODULE_LICENSE("GPL v2");