0001
0002
0003
0004
0005
0006 #include <linux/clk.h>
0007 #include <linux/interrupt.h>
0008 #include <linux/iopoll.h>
0009 #include <linux/module.h>
0010 #include <linux/platform_device.h>
0011 #include <linux/of_device.h>
0012 #include <linux/of_irq.h>
0013 #include <linux/of_address.h>
0014
0015 #define VIO_MOD_TO_REG_IND(m) ((m) / 32)
0016 #define VIO_MOD_TO_REG_OFF(m) ((m) % 32)
0017
0018 struct mtk_devapc_vio_dbgs {
0019 union {
0020 u32 vio_dbg0;
0021 struct {
0022 u32 mstid:16;
0023 u32 dmnid:6;
0024 u32 vio_w:1;
0025 u32 vio_r:1;
0026 u32 addr_h:4;
0027 u32 resv:4;
0028 } dbg0_bits;
0029 };
0030
0031 u32 vio_dbg1;
0032 };
0033
0034 struct mtk_devapc_regs_ofs {
0035
0036 u32 vio_mask_offset;
0037 u32 vio_sta_offset;
0038 u32 vio_dbg0_offset;
0039 u32 vio_dbg1_offset;
0040 u32 apc_con_offset;
0041 u32 vio_shift_sta_offset;
0042 u32 vio_shift_sel_offset;
0043 u32 vio_shift_con_offset;
0044 };
0045
0046 struct mtk_devapc_data {
0047
0048 u32 vio_idx_num;
0049 const struct mtk_devapc_regs_ofs *regs_ofs;
0050 };
0051
0052 struct mtk_devapc_context {
0053 struct device *dev;
0054 void __iomem *infra_base;
0055 struct clk *infra_clk;
0056 const struct mtk_devapc_data *data;
0057 };
0058
0059 static void clear_vio_status(struct mtk_devapc_context *ctx)
0060 {
0061 void __iomem *reg;
0062 int i;
0063
0064 reg = ctx->infra_base + ctx->data->regs_ofs->vio_sta_offset;
0065
0066 for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
0067 writel(GENMASK(31, 0), reg + 4 * i);
0068
0069 writel(GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1, 0),
0070 reg + 4 * i);
0071 }
0072
0073 static void mask_module_irq(struct mtk_devapc_context *ctx, bool mask)
0074 {
0075 void __iomem *reg;
0076 u32 val;
0077 int i;
0078
0079 reg = ctx->infra_base + ctx->data->regs_ofs->vio_mask_offset;
0080
0081 if (mask)
0082 val = GENMASK(31, 0);
0083 else
0084 val = 0;
0085
0086 for (i = 0; i < VIO_MOD_TO_REG_IND(ctx->data->vio_idx_num) - 1; i++)
0087 writel(val, reg + 4 * i);
0088
0089 val = readl(reg + 4 * i);
0090 if (mask)
0091 val |= GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
0092 0);
0093 else
0094 val &= ~GENMASK(VIO_MOD_TO_REG_OFF(ctx->data->vio_idx_num) - 1,
0095 0);
0096
0097 writel(val, reg + 4 * i);
0098 }
0099
0100 #define PHY_DEVAPC_TIMEOUT 0x10000
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112 static int devapc_sync_vio_dbg(struct mtk_devapc_context *ctx)
0113 {
0114 void __iomem *pd_vio_shift_sta_reg;
0115 void __iomem *pd_vio_shift_sel_reg;
0116 void __iomem *pd_vio_shift_con_reg;
0117 int min_shift_group;
0118 int ret;
0119 u32 val;
0120
0121 pd_vio_shift_sta_reg = ctx->infra_base +
0122 ctx->data->regs_ofs->vio_shift_sta_offset;
0123 pd_vio_shift_sel_reg = ctx->infra_base +
0124 ctx->data->regs_ofs->vio_shift_sel_offset;
0125 pd_vio_shift_con_reg = ctx->infra_base +
0126 ctx->data->regs_ofs->vio_shift_con_offset;
0127
0128
0129 val = readl(pd_vio_shift_sta_reg);
0130 if (!val)
0131 return false;
0132
0133 min_shift_group = __ffs(val);
0134
0135
0136 writel(0x1 << min_shift_group, pd_vio_shift_sel_reg);
0137
0138
0139 writel(0x1, pd_vio_shift_con_reg);
0140
0141 ret = readl_poll_timeout(pd_vio_shift_con_reg, val, val == 0x3, 0,
0142 PHY_DEVAPC_TIMEOUT);
0143 if (ret) {
0144 dev_err(ctx->dev, "%s: Shift violation info failed\n", __func__);
0145 return false;
0146 }
0147
0148
0149 writel(0x0, pd_vio_shift_con_reg);
0150
0151
0152 writel(0x1 << min_shift_group, pd_vio_shift_sta_reg);
0153
0154 return true;
0155 }
0156
0157
0158
0159
0160
0161 static void devapc_extract_vio_dbg(struct mtk_devapc_context *ctx)
0162 {
0163 struct mtk_devapc_vio_dbgs vio_dbgs;
0164 void __iomem *vio_dbg0_reg;
0165 void __iomem *vio_dbg1_reg;
0166
0167 vio_dbg0_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg0_offset;
0168 vio_dbg1_reg = ctx->infra_base + ctx->data->regs_ofs->vio_dbg1_offset;
0169
0170 vio_dbgs.vio_dbg0 = readl(vio_dbg0_reg);
0171 vio_dbgs.vio_dbg1 = readl(vio_dbg1_reg);
0172
0173
0174 if (vio_dbgs.dbg0_bits.vio_w)
0175 dev_info(ctx->dev, "Write Violation\n");
0176 else if (vio_dbgs.dbg0_bits.vio_r)
0177 dev_info(ctx->dev, "Read Violation\n");
0178
0179 dev_info(ctx->dev, "Bus ID:0x%x, Dom ID:0x%x, Vio Addr:0x%x\n",
0180 vio_dbgs.dbg0_bits.mstid, vio_dbgs.dbg0_bits.dmnid,
0181 vio_dbgs.vio_dbg1);
0182 }
0183
0184
0185
0186
0187
0188
0189 static irqreturn_t devapc_violation_irq(int irq_number, void *data)
0190 {
0191 struct mtk_devapc_context *ctx = data;
0192
0193 while (devapc_sync_vio_dbg(ctx))
0194 devapc_extract_vio_dbg(ctx);
0195
0196 clear_vio_status(ctx);
0197
0198 return IRQ_HANDLED;
0199 }
0200
0201
0202
0203
0204 static void start_devapc(struct mtk_devapc_context *ctx)
0205 {
0206 writel(BIT(31), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
0207
0208 mask_module_irq(ctx, false);
0209 }
0210
0211
0212
0213
0214 static void stop_devapc(struct mtk_devapc_context *ctx)
0215 {
0216 mask_module_irq(ctx, true);
0217
0218 writel(BIT(2), ctx->infra_base + ctx->data->regs_ofs->apc_con_offset);
0219 }
0220
0221 static const struct mtk_devapc_regs_ofs devapc_regs_ofs_mt6779 = {
0222 .vio_mask_offset = 0x0,
0223 .vio_sta_offset = 0x400,
0224 .vio_dbg0_offset = 0x900,
0225 .vio_dbg1_offset = 0x904,
0226 .apc_con_offset = 0xF00,
0227 .vio_shift_sta_offset = 0xF10,
0228 .vio_shift_sel_offset = 0xF14,
0229 .vio_shift_con_offset = 0xF20,
0230 };
0231
0232 static const struct mtk_devapc_data devapc_mt6779 = {
0233 .vio_idx_num = 511,
0234 .regs_ofs = &devapc_regs_ofs_mt6779,
0235 };
0236
0237 static const struct mtk_devapc_data devapc_mt8186 = {
0238 .vio_idx_num = 519,
0239 .regs_ofs = &devapc_regs_ofs_mt6779,
0240 };
0241
0242 static const struct of_device_id mtk_devapc_dt_match[] = {
0243 {
0244 .compatible = "mediatek,mt6779-devapc",
0245 .data = &devapc_mt6779,
0246 }, {
0247 .compatible = "mediatek,mt8186-devapc",
0248 .data = &devapc_mt8186,
0249 }, {
0250 },
0251 };
0252 MODULE_DEVICE_TABLE(of, mtk_devapc_dt_match);
0253
0254 static int mtk_devapc_probe(struct platform_device *pdev)
0255 {
0256 struct device_node *node = pdev->dev.of_node;
0257 struct mtk_devapc_context *ctx;
0258 u32 devapc_irq;
0259 int ret;
0260
0261 if (IS_ERR(node))
0262 return -ENODEV;
0263
0264 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
0265 if (!ctx)
0266 return -ENOMEM;
0267
0268 ctx->data = of_device_get_match_data(&pdev->dev);
0269 ctx->dev = &pdev->dev;
0270
0271 ctx->infra_base = of_iomap(node, 0);
0272 if (!ctx->infra_base)
0273 return -EINVAL;
0274
0275 devapc_irq = irq_of_parse_and_map(node, 0);
0276 if (!devapc_irq)
0277 return -EINVAL;
0278
0279 ctx->infra_clk = devm_clk_get(&pdev->dev, "devapc-infra-clock");
0280 if (IS_ERR(ctx->infra_clk))
0281 return -EINVAL;
0282
0283 if (clk_prepare_enable(ctx->infra_clk))
0284 return -EINVAL;
0285
0286 ret = devm_request_irq(&pdev->dev, devapc_irq, devapc_violation_irq,
0287 IRQF_TRIGGER_NONE, "devapc", ctx);
0288 if (ret) {
0289 clk_disable_unprepare(ctx->infra_clk);
0290 return ret;
0291 }
0292
0293 platform_set_drvdata(pdev, ctx);
0294
0295 start_devapc(ctx);
0296
0297 return 0;
0298 }
0299
0300 static int mtk_devapc_remove(struct platform_device *pdev)
0301 {
0302 struct mtk_devapc_context *ctx = platform_get_drvdata(pdev);
0303
0304 stop_devapc(ctx);
0305
0306 clk_disable_unprepare(ctx->infra_clk);
0307
0308 return 0;
0309 }
0310
0311 static struct platform_driver mtk_devapc_driver = {
0312 .probe = mtk_devapc_probe,
0313 .remove = mtk_devapc_remove,
0314 .driver = {
0315 .name = "mtk-devapc",
0316 .of_match_table = mtk_devapc_dt_match,
0317 },
0318 };
0319
0320 module_platform_driver(mtk_devapc_driver);
0321
0322 MODULE_DESCRIPTION("Mediatek Device APC Driver");
0323 MODULE_AUTHOR("Neal Liu <neal.liu@mediatek.com>");
0324 MODULE_LICENSE("GPL");