1 #include <linux/kernel.h>
2 #include <linux/module.h>
3 #include <linux/interrupt.h>
4 #include <linux/device.h>
5 #include <linux/platform_device.h>
7 #include <linux/uaccess.h>
8 #include <linux/slab.h>
9 #include <linux/spinlock.h>
10 #include <linux/irq.h>
11 #include <linux/sched.h>
12 #include <linux/list.h>
13 #ifdef CONFIG_MTK_AEE_FEATURE
14 #include <linux/aee.h>
16 #include <linux/timer.h>
17 #include <linux/workqueue.h>
19 #include <mach/mt_reg_base.h>
20 #include <mach/emi_mpu.h>
21 #include <mach/mt_device_apc.h>
22 #include <mach/sync_write.h>
23 #include <mach/irqs.h>
26 #define NR_REGION_ABORT 8
27 #define MAX_EMI_MPU_STORE_CMD_LEN 128
28 #define ABORT_EMI_BUS_INTERFACE 0x00800000 //DEVAPC0_D0_VIO_STA_0, idx:23
29 #define ABORT_EMI 0x00002000 //DEVAPC0_D0_VIO_STA_3, idx:13
31 #define AXI_VIO_MONITOR_TIME (1 * HZ)
33 static struct work_struct emi_mpu_work
;
34 static struct workqueue_struct
* emi_mpu_workqueue
= NULL
;
36 static unsigned int vio_addr
;
47 struct emi_mpu_notifier_block
49 struct list_head list
;
50 emi_mpu_notifier notifier
;
53 static const struct mst_tbl_entry mst_tbl
[] =
56 { .master
= MST_ID_APMCU_0
, .port
= 0x0, .id_mask
= 0b11111100, .id_val
= 0b00000000, .name
= "APMCU: Processor Non-Cacheable or STREX" },
57 { .master
= MST_ID_APMCU_1
, .port
= 0x0, .id_mask
= 0b11111100, .id_val
= 0b00000100, .name
= "APMCU: Processor write to device and Strongly_ordered memory" },
58 { .master
= MST_ID_APMCU_2
, .port
= 0x0, .id_mask
= 0b11111100, .id_val
= 0b00001000, .name
= "APMCU: Processor write portion of the barrier transactions" },
59 { .master
= MST_ID_APMCU_3
, .port
= 0x0, .id_mask
= 0b11111111, .id_val
= 0b00001111, .name
= "APMCU: Write portion of barrier caused by external DVM synchronization" },
60 { .master
= MST_ID_APMCU_4
, .port
= 0x0, .id_mask
= 0b11110000, .id_val
= 0b00010000, .name
= "APMCU: Write to cacheable memory from write address buffer" },
63 { .master
= MST_ID_MM_0
, .port
= 0x1, .id_mask
= 0b11100000, .id_val
= 0b01100000, .name
= "Larb0 MM Master, MMSYS" },
64 { .master
= MST_ID_MM_1
, .port
= 0x1, .id_mask
= 0b11100000, .id_val
= 0b01000000, .name
= "Larb1 MM Master, VDEC" },
65 { .master
= MST_ID_MM_2
, .port
= 0x1, .id_mask
= 0b11100000, .id_val
= 0b00100000, .name
= "Larb2 MM Master, ISP+VENC" },
66 { .master
= MST_ID_MM_3
, .port
= 0x1, .id_mask
= 0b11100000, .id_val
= 0b00000000, .name
= "G3D Master" },
67 { .master
= MST_ID_MM_4
, .port
= 0x1, .id_mask
= 0b11111111, .id_val
= 0b11111101, .name
= "M4U" },
68 { .master
= MST_ID_MM_5
, .port
= 0x1, .id_mask
= 0b11111111, .id_val
= 0b11111110, .name
= "M4U" },
69 { .master
= MST_ID_MM_6
, .port
= 0x1, .id_mask
= 0b11111111, .id_val
= 0b11111100, .name
= "M4U" },
72 { .master
= MST_ID_PERI_0
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00000000, .name
= "NFI" },
73 { .master
= MST_ID_PERI_1
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00001000, .name
= "MSDC0" }, /* MT6582:ask MSDC owner to remove emi_mpu_notifier_register and modify enum name */
74 { .master
= MST_ID_PERI_2
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00010000, .name
= "Audio" },
75 { .master
= MST_ID_PERI_3
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00011000, .name
= "USB2.0" },
76 { .master
= MST_ID_PERI_4
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00000010, .name
= "PWM" },
77 { .master
= MST_ID_PERI_5
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00001010, .name
= "MSDC1" },
78 { .master
= MST_ID_PERI_6
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00010010, .name
= "MSDC2" },
79 { .master
= MST_ID_PERI_7
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00011010, .name
= "SPI0" },
80 { .master
= MST_ID_PERI_8
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00000100, .name
= "MD" },
81 { .master
= MST_ID_PERI_9
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00001100, .name
= "SPM,FHCTL" },
82 { .master
= MST_ID_PERI_10
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00010100, .name
= "DBG" },
83 { .master
= MST_ID_PERI_11
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00011100, .name
= "THERM" },
84 { .master
= MST_ID_PERI_12
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00000110, .name
= "DMA" },
85 { .master
= MST_ID_PERI_13
, .port
= 0x2, .id_mask
= 0b11111111, .id_val
= 0b00000001, .name
= "Conn2AP" },
88 { .master
= MST_ID_MDMCU_0
, .port
= 0x3, .id_mask
= 0b00000000, .id_val
= 0b00000000, .name
= "MDMCU" },
90 /* Modem HW (2G/3G) */
91 { .master
= MST_ID_MDHW_0
, .port
= 0x4, .id_mask
= 0b00000000, .id_val
= 0b00000000, .name
= "MDHW" },
94 //struct list_head emi_mpu_notifier_list[NR_MST];
95 static const char *UNKNOWN_MASTER
= "unknown";
96 static spinlock_t emi_mpu_lock
;
98 struct timer_list emi_axi_vio_timer
;
100 char *smi_larb0_port
[9] = {"disp_ovl_0", "disp_rdma", "disp_wdma", "mm_cmdq", "mdp_rdma", "mdp_wdma", "mdp_roto", "mdp_rotco", "mdp_rotvo"};
101 char *smi_larb1_port
[7] = {"hw_vdec_mc_ext", "hw_vdec_pp_ext", "hw_vdec_avc_mv_ext", "hw_vdec_pred_rd_ext", "hw_vdec_pred_wr_ext", "hw_vdec_vld_ext", "hw_vdec_pp_int" };
102 char *smi_larb2_port
[17] = {"cam_imgo", "cam_img2o", "cam_lsci", "cam_imgi", "cam_esfko", "cam_aao", "jpgenc_rdma", "jpgenc_bsdma", "venc_rd_comv", "venc_sv_comv",
103 "venc_rcpu", "venc_rec_frm", "venc_ref_luma", "venc_ref_chroma", "venc_bsdma", "venc_cur_luma", "venc_cur_chroma"};
105 static int __match_id(u32 axi_id
, int tbl_idx
, u32 port_ID
)
110 if (((axi_id
& mst_tbl
[tbl_idx
].id_mask
) == mst_tbl
[tbl_idx
].id_val
) && (port_ID
== mst_tbl
[tbl_idx
].port
))
115 case 2: /* Peripheral */
117 case 4: /* MD HW (2G/3G) */
118 printk(KERN_CRIT
"Violation master name is %s.\n", mst_tbl
[tbl_idx
].name
);
122 smi_port
= axi_id
& 0x1F;
125 if(smi_port
>= ARRAY_SIZE(smi_larb0_port
))
127 printk(KERN_CRIT
"[EMI MPU ERROR] Invalidate master ID! lookup smi table failed!\n");
130 printk(KERN_CRIT
"Violation master name is %s (%s).\n", mst_tbl
[tbl_idx
].name
, smi_larb0_port
[smi_port
]);
132 else if(mm_larb
== 0x2)
134 if(smi_port
>= ARRAY_SIZE(smi_larb1_port
))
136 printk(KERN_CRIT
"[EMI MPU ERROR] Invalidate master ID! lookup smi table failed!\n");
139 printk(KERN_CRIT
"Violation master name is %s (%s).\n", mst_tbl
[tbl_idx
].name
, smi_larb1_port
[smi_port
]);
141 else if(mm_larb
== 0x1)
143 if(smi_port
>= ARRAY_SIZE(smi_larb2_port
))
145 printk(KERN_CRIT
"[EMI MPU ERROR] Invalidate master ID! lookup smi table failed!\n");
148 printk(KERN_CRIT
"Violation master name is %s (%s).\n", mst_tbl
[tbl_idx
].name
, smi_larb2_port
[smi_port
]);
152 printk(KERN_CRIT
"Violation master name is %s.\n", mst_tbl
[tbl_idx
].name
);
156 printk(KERN_CRIT
"[EMI MPU ERROR] Invalidate port ID! lookup bus ID table failed!\n");
167 #if 1 //#ifndef CONFIG_MT8127_EVB_BOARD
168 static u32
__id2mst(u32 id
)
174 axi_ID
= (id
>> 3) & 0x000000FF;
175 port_ID
= id
& 0x00000007;
177 printk("[EMI MPU] axi_id = %x, port_id = %x\n", axi_ID
, port_ID
);
179 for (i
= 0; i
< ARRAY_SIZE(mst_tbl
); i
++) {
180 if (__match_id(axi_ID
, i
, port_ID
)) {
181 return mst_tbl
[i
].master
;
188 static char *__id2name(u32 id
)
194 axi_ID
= (id
>> 3) & 0x000000FF;
195 port_ID
= id
& 0x00000007;
197 printk("[EMI MPU] axi_id = %x, port_id = %x\n", axi_ID
, port_ID
);
199 for (i
= 0; i
< ARRAY_SIZE(mst_tbl
); i
++) {
200 if (__match_id(axi_ID
, i
, port_ID
))
202 return mst_tbl
[i
].name
;
206 return (char *)UNKNOWN_MASTER
;
209 static void __clear_emi_mpu_vio(void)
213 /* clear violation status */
214 mt65xx_reg_sync_writel(0x000003FF, EMI_MPUP
);
215 mt65xx_reg_sync_writel(0x000003FF, EMI_MPUQ
);
216 mt65xx_reg_sync_writel(0x000003FF, EMI_MPUR
);
217 mt65xx_reg_sync_writel(0x000003FF, EMI_MPUY
);
219 /* clear debug info */
220 mt65xx_reg_sync_writel(0x80000000 , EMI_MPUS
);
221 dbg_s
= readl(IOMEM(EMI_MPUS
));
222 dbg_t
= readl(IOMEM(EMI_MPUT
));
224 /* MT6582 EMI hw bug that EMI_MPUS[10:0] and EMI_MPUT can't be cleared */
227 printk(KERN_CRIT
"Fail to clear EMI MPU violation\n");
228 printk(KERN_CRIT
"EMI_MPUS = %x, EMI_MPUT = %x", dbg_s
, dbg_t
);
232 /*EMI MPU violation handler*/
233 #if 1 //#ifndef CONFIG_MT8127_EVB_BOARD
234 static irqreturn_t
mpu_violation_irq(int irq
, void *dev_id
)
236 u32 dbg_s
, dbg_t
, dbg_pqry
;
237 u32 master_ID
, domain_ID
, wr_vio
;
242 // Hong-Rong: need DEVAPC owner porting
243 if ((readl(IOMEM(DEVAPC0_D0_VIO_STA_0
)) & ABORT_EMI_BUS_INTERFACE
) == 0
244 && (readl(IOMEM(DEVAPC0_D0_VIO_STA_3
)) & ABORT_EMI
) == 0) {
245 printk(KERN_INFO
"Not EMI MPU violation.\n");
250 dbg_s
= readl(IOMEM(EMI_MPUS
));
251 dbg_t
= readl(IOMEM(EMI_MPUT
));
253 master_ID
= dbg_s
& 0x000007FF;
254 domain_ID
= (dbg_s
>> 12) & 0x00000003;
255 wr_vio
= (dbg_s
>> 28) & 0x00000003;
256 region
= (dbg_s
>> 16) & 0xFF;
258 for (i
= 0 ; i
< NR_REGION_ABORT
; i
++) {
259 if ((region
>> i
) & 1) {
263 region
= (i
>= NR_REGION_ABORT
)? -1: i
;
267 dbg_pqry
= readl(IOMEM(EMI_MPUP
));
270 dbg_pqry
= readl(IOMEM(EMI_MPUQ
));
273 dbg_pqry
= readl(IOMEM(EMI_MPUR
));
276 dbg_pqry
= readl(IOMEM(EMI_MPUY
));
283 /*TBD: print the abort region*/
285 printk(KERN_CRIT
"EMI MPU violation.\n");
286 printk(KERN_CRIT
"[EMI MPU] Debug info start ----------------------------------------\n");
288 printk(KERN_CRIT
"EMI_MPUS = %x, EMI_MPUT = %x.\n", dbg_s
, dbg_t
);
289 printk(KERN_CRIT
"Current process is \"%s \" (pid: %i).\n", current
->comm
, current
->pid
);
290 printk(KERN_CRIT
"Violation address is 0x%x.\n", dbg_t
+ EMI_PHY_OFFSET
);
291 printk(KERN_CRIT
"Violation master ID is 0x%x.\n", master_ID
);
292 /*print out the murderer name*/
293 master_name
= __id2name(master_ID
);
294 printk(KERN_CRIT
"Violation domain ID is 0x%x.\n", domain_ID
);
295 printk(KERN_CRIT
"%s violation.\n", (wr_vio
== 1)? "Write": "Read");
296 printk(KERN_CRIT
"Corrupted region is %d\n\r", region
);
297 if (dbg_pqry
& OOR_VIO
) {
298 printk(KERN_CRIT
"Out of range violation.\n");
300 printk(KERN_CRIT
"[EMI MPU] Debug info end------------------------------------------\n");
302 #ifdef CONFIG_MTK_AEE_FEATURE
303 //aee_kernel_exception("EMI MPU", "EMI MPU violation.\nEMP_MPUS = 0x%x, EMI_MPUT = 0x%x, EMI_MPU(PQR).\n", dbg_s, dbg_t+EMI_PHY_OFFSET, dbg_pqry);
304 aee_kernel_exception("EMI MPU", "EMI MPU violation.\nEMP_MPUS = 0x%x, EMI_MPUT = 0x%x, module is %s.\n", dbg_s
, dbg_t
+EMI_PHY_OFFSET
, master_name
);
307 __clear_emi_mpu_vio();
310 if ((readl(IOMEM(DEVAPC0_D0_VIO_STA_0
)) & ABORT_EMI_BUS_INTERFACE
) != 0)
312 mt65xx_reg_sync_writel(ABORT_EMI_BUS_INTERFACE
, DEVAPC0_D0_VIO_STA_0
);
315 if ((readl(IOMEM(DEVAPC0_D0_VIO_STA_3
)) & ABORT_EMI
) != 0)
317 mt65xx_reg_sync_writel(ABORT_EMI
, DEVAPC0_D0_VIO_STA_3
);
320 printk("[EMI MPU] _id2mst = %d\n", __id2mst(master_ID
));
322 #if 0 //Marcos(MT6582): Each hw module has an unique ID. There is no need to use notifier function to distinguish different hw module which has the same bus ID.
323 list_for_each(p
, &(emi_mpu_notifier_list
[__id2mst(master_ID
)])) {
324 block
= list_entry(p
, struct emi_mpu_notifier_block
, list
);
325 block
->notifier(dbg_t
+ EMI_PHY_OFFSET
, wr_vio
);
329 vio_addr
= dbg_t
+ EMI_PHY_OFFSET
;
336 * emi_mpu_set_region_protection: protect a region.
337 * @start: start address of the region
338 * @end: end address of the region
339 * @region: EMI MPU region id
340 * @access_permission: EMI MPU access permission
341 * Return 0 for success, otherwise negative status code.
343 int emi_mpu_set_region_protection(unsigned int start
, unsigned int end
, int region
, unsigned int access_permission
)
349 if((end
!= 0) || (start
!=0)) {
350 /*Address 64KB alignment*/
351 start
-= EMI_PHY_OFFSET
;
352 end
-= EMI_PHY_OFFSET
;
361 spin_lock_irqsave(&emi_mpu_lock
, flags
);
365 //Marcos: Clear access right before setting MPU address (Mt6582 design)
366 tmp
= readl(IOMEM(EMI_MPUI
)) & 0xFFFF0000;
367 mt65xx_reg_sync_writel(0, EMI_MPUI
);
368 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUA
);
369 mt65xx_reg_sync_writel(tmp
| access_permission
, EMI_MPUI
);
373 //Marcos: Clear access right before setting MPU address (Mt6582 design)
374 tmp
= readl(IOMEM(EMI_MPUI
)) & 0x0000FFFF;
375 mt65xx_reg_sync_writel(0, EMI_MPUI
);
376 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUB
);
377 mt65xx_reg_sync_writel(tmp
| (access_permission
<< 16), EMI_MPUI
);
381 //Marcos: Clear access right before setting MPU address (Mt6582 design)
382 tmp
= readl(IOMEM(EMI_MPUJ
)) & 0xFFFF0000;
383 mt65xx_reg_sync_writel(0, EMI_MPUJ
);
384 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUC
);
385 mt65xx_reg_sync_writel(tmp
| access_permission
, EMI_MPUJ
);
389 //Marcos: Clear access right before setting MPU address (Mt6582 design)
390 tmp
= readl(IOMEM(EMI_MPUJ
)) & 0x0000FFFF;
391 mt65xx_reg_sync_writel(0, EMI_MPUJ
);
392 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUD
);
393 mt65xx_reg_sync_writel(tmp
| (access_permission
<< 16), EMI_MPUJ
);
397 //Marcos: Clear access right before setting MPU address (Mt6582 design)
398 tmp
= readl(IOMEM(EMI_MPUK
)) & 0xFFFF0000;
399 mt65xx_reg_sync_writel(0, EMI_MPUK
);
400 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUE
);
401 mt65xx_reg_sync_writel(tmp
| access_permission
, EMI_MPUK
);
405 //Marcos: Clear access right before setting MPU address (Mt6582 design)
406 tmp
= readl(IOMEM(EMI_MPUK
)) & 0x0000FFFF;
407 mt65xx_reg_sync_writel(0, EMI_MPUK
);
408 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUF
);
409 mt65xx_reg_sync_writel(tmp
| (access_permission
<< 16), EMI_MPUK
);
413 //Marcos: Clear access right before setting MPU address (Mt6582 design)
414 tmp
= readl(IOMEM(EMI_MPUL
)) & 0xFFFF0000;
415 mt65xx_reg_sync_writel(0, EMI_MPUL
);
416 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUG
);
417 mt65xx_reg_sync_writel(tmp
| access_permission
, EMI_MPUL
);
421 //Marcos: Clear access right before setting MPU address (Mt6582 design)
422 tmp
= readl(IOMEM(EMI_MPUL
)) & 0x0000FFFF;
423 mt65xx_reg_sync_writel(0, EMI_MPUL
);
424 mt65xx_reg_sync_writel((start
<< 16) | end
, EMI_MPUH
);
425 mt65xx_reg_sync_writel(tmp
| (access_permission
<< 16), EMI_MPUL
);
433 spin_unlock_irqrestore(&emi_mpu_lock
, flags
);
439 * emi_mpu_notifier_register: register a notifier.
441 * notifier: the callback function
442 * Return 0 for success, otherwise negative error code.
445 int emi_mpu_notifier_register(int master
, emi_mpu_notifier notifier
)
447 struct emi_mpu_notifier_block
*block
;
448 static int emi_mpu_notifier_init
= 0;
451 if (master
>= MST_INVALID
) {
455 block
= kmalloc(sizeof(struct emi_mpu_notifier_block
), GFP_KERNEL
);
460 if (!emi_mpu_notifier_init
) {
461 for (i
= 0; i
< NR_MST
; i
++) {
462 INIT_LIST_HEAD(&(emi_mpu_notifier_list
[i
]));
464 emi_mpu_notifier_init
= 1;
467 block
->notifier
= notifier
;
468 list_add(&(block
->list
), &(emi_mpu_notifier_list
[master
]));
474 static ssize_t
emi_mpu_show(struct device_driver
*driver
, char *buf
)
477 unsigned int start
, end
;
478 unsigned int reg_value
;
479 unsigned int d0
, d1
, d2
, d3
;
480 static const char *permission
[6] =
483 "Only R/W for secure access",
484 "Only R/W for secure access, and non-secure read access",
485 "Only R/W for secure access, and non-secure write access",
486 "Only R for secure/non-secure",
487 "Both R/W are forbidden"
490 reg_value
= readl(IOMEM(EMI_MPUA
));
491 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
492 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
493 ptr
+= sprintf(ptr
, "Region 0 --> 0x%x to 0x%x\n", start
, end
);
495 reg_value
= readl(IOMEM(EMI_MPUB
));
496 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
497 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
498 ptr
+= sprintf(ptr
, "Region 1 --> 0x%x to 0x%x\n", start
, end
);
500 reg_value
= readl(IOMEM(EMI_MPUC
));
501 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
502 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
503 ptr
+= sprintf(ptr
, "Region 2 --> 0x%x to 0x%x\n", start
, end
);
505 reg_value
= readl(IOMEM(EMI_MPUD
));
506 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
507 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
508 ptr
+= sprintf(ptr
, "Region 3 --> 0x%x to 0x%x\n", start
, end
);
510 reg_value
= readl(IOMEM(EMI_MPUE
));
511 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
512 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
513 ptr
+= sprintf(ptr
, "Region 4 --> 0x%x to 0x%x\n", start
, end
);
515 reg_value
= readl(IOMEM(EMI_MPUF
));
516 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
517 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
518 ptr
+= sprintf(ptr
, "Region 5 --> 0x%x to 0x%x\n", start
, end
);
520 reg_value
= readl(IOMEM(EMI_MPUG
));
521 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
522 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
523 ptr
+= sprintf(ptr
, "Region 6 --> 0x%x to 0x%x\n", start
, end
);
525 reg_value
= readl(IOMEM(EMI_MPUH
));
526 start
= ((reg_value
>> 16) << 16) + EMI_PHY_OFFSET
;
527 end
= ((reg_value
& 0xFFFF) << 16) + EMI_PHY_OFFSET
;
528 ptr
+= sprintf(ptr
, "Region 7 --> 0x%x to 0x%x\n", start
, end
);
530 ptr
+= sprintf (ptr
, "\n");
532 reg_value
= readl(IOMEM(EMI_MPUI
));
533 d0
= (reg_value
& 0x7);
534 d1
= (reg_value
>> 3) & 0x7;
535 d2
= (reg_value
>> 6) & 0x7;
536 d3
= (reg_value
>> 9) & 0x7;
537 ptr
+= sprintf(ptr
, "Region 0 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
539 d0
= ((reg_value
>>16) & 0x7);
540 d1
= ((reg_value
>>16) >> 3) & 0x7;
541 d2
= ((reg_value
>>16) >> 6) & 0x7;
542 d3
= ((reg_value
>>16) >> 9) & 0x7;
543 ptr
+= sprintf(ptr
, "Region 1 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
545 reg_value
= readl(IOMEM(EMI_MPUJ
));
546 d0
= (reg_value
& 0x7);
547 d1
= (reg_value
>> 3) & 0x7;
548 d2
= (reg_value
>> 6) & 0x7;
549 d3
= (reg_value
>> 9) & 0x7;
550 ptr
+= sprintf(ptr
, "Region 2 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
552 d0
= ((reg_value
>>16) & 0x7);
553 d1
= ((reg_value
>>16) >> 3) & 0x7;
554 d2
= ((reg_value
>>16) >> 6) & 0x7;
555 d3
= ((reg_value
>>16) >> 9) & 0x7;
556 ptr
+= sprintf(ptr
, "Region 3 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
558 reg_value
= readl(IOMEM(EMI_MPUK
));
559 d0
= (reg_value
& 0x7);
560 d1
= (reg_value
>> 3) & 0x7;
561 d2
= (reg_value
>> 6) & 0x7;
562 d3
= (reg_value
>> 9) & 0x7;
563 ptr
+= sprintf(ptr
, "Region 4 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
565 d0
= ((reg_value
>>16) & 0x7);
566 d1
= ((reg_value
>>16) >> 3) & 0x7;
567 d2
= ((reg_value
>>16) >> 6) & 0x7;
568 d3
= ((reg_value
>>16) >> 9) & 0x7;
569 ptr
+= sprintf(ptr
, "Region 5 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
571 reg_value
= readl(IOMEM(EMI_MPUL
));
572 d0
= (reg_value
& 0x7);
573 d1
= (reg_value
>> 3) & 0x7;
574 d2
= (reg_value
>> 6) & 0x7;
575 d3
= (reg_value
>> 9) & 0x7;
576 ptr
+= sprintf(ptr
, "Region 6 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
578 d0
= ((reg_value
>>16) & 0x7);
579 d1
= ((reg_value
>>16) >> 3) & 0x7;
580 d2
= ((reg_value
>>16) >> 6) & 0x7;
581 d3
= ((reg_value
>>16) >> 9) & 0x7;
582 ptr
+= sprintf(ptr
, "Region 7 --> d0 = %s, d1 = %s, d2 = %s, d3 = %s\n", permission
[d0
], permission
[d1
], permission
[d2
], permission
[d3
]);
587 static ssize_t
emi_mpu_store(struct device_driver
*driver
, const char *buf
, size_t count
)
590 unsigned int start_addr
;
591 unsigned int end_addr
;
593 unsigned int access_permission
;
598 if ((strlen(buf
) + 1) > MAX_EMI_MPU_STORE_CMD_LEN
) {
599 printk(KERN_CRIT
"emi_mpu_store command overflow.");
602 printk(KERN_CRIT
"emi_mpu_store: %s\n", buf
);
604 command
= kmalloc((size_t)MAX_EMI_MPU_STORE_CMD_LEN
, GFP_KERNEL
);
608 strcpy(command
, buf
);
611 if (!strncmp(buf
, EN_MPU_STR
, strlen(EN_MPU_STR
))) {
613 while (ptr
!= NULL
) {
614 ptr
= strsep(&command
, " ");
616 printk(KERN_DEBUG
"token[%d] = %s\n", i
, token
[i
]);
619 for (i
= 0; i
< 5; i
++) {
620 printk(KERN_DEBUG
"token[%d] = %s\n", i
, token
[i
]);
623 start_addr
= simple_strtoul(token
[1], &token
[1], 16);
624 end_addr
= simple_strtoul(token
[2], &token
[2], 16);
625 region
= simple_strtoul(token
[3], &token
[3], 16);
626 access_permission
= simple_strtoul(token
[4], &token
[4], 16);
627 emi_mpu_set_region_protection(start_addr
, end_addr
, region
, access_permission
);
628 printk(KERN_CRIT
"Set EMI_MPU: start: 0x%x, end: 0x%x, region: %d, permission: 0x%x.\n", start_addr
, end_addr
, region
, access_permission
);
629 } else if (!strncmp(buf
, DIS_MPU_STR
, strlen(DIS_MPU_STR
))) {
631 while (ptr
!= NULL
) {
632 ptr
= strsep (&command
, " ");
634 printk(KERN_DEBUG
"token[%d] = %s\n", i
, token
[i
]);
637 for (i
= 0;i
< 5; i
++) {
638 printk(KERN_DEBUG
"token[%d] = %s\n", i
, token
[i
]);
641 start_addr
= simple_strtoul(token
[1], &token
[1], 16);
642 end_addr
= simple_strtoul(token
[2], &token
[2], 16);
643 region
= simple_strtoul(token
[3], &token
[3], 16);
644 emi_mpu_set_region_protection(0x0, 0x0, region
, SET_ACCESS_PERMISSON(NO_PROTECTION
, NO_PROTECTION
, NO_PROTECTION
, NO_PROTECTION
));
645 printk("set EMI MPU: start: 0x%x, end: 0x%x, region: %d, permission: 0x%x\n", 0, 0, region
, SET_ACCESS_PERMISSON(NO_PROTECTION
, NO_PROTECTION
, NO_PROTECTION
, NO_PROTECTION
));
647 printk(KERN_CRIT
"Unknown emi_mpu command.\n");
655 DRIVER_ATTR(mpu_config
, 0644, emi_mpu_show
, emi_mpu_store
);
657 void mtk_search_full_pgtab(void)
664 unsigned long addr_2nd
, addr_2nd_end
;
665 unsigned int v_addr
= vio_addr
;
668 //vio_addr = 0x9DE0D000;
670 for(addr
=0xC0000000; addr
<0xFFF00000; addr
+=0x100000)
672 pgd
= pgd_offset(&init_mm
, addr
);
673 if (pgd_none(*pgd
) || !pgd_present(*pgd
))
678 pud
= pud_offset(pgd
, addr
);
679 if (pud_none(*pud
) || !pud_present(*pud
))
684 pmd
= pmd_offset(pud
, addr
);
685 if (pmd_none(*pmd
) || !pmd_present(*pmd
))
690 //printk("[EMI MPU] ============= addr = %x\n", addr);
692 #ifndef CONFIG_ARM_LPAE
693 if ((pmd_val(*pmd
) & PMD_TYPE_MASK
) == PMD_TYPE_TABLE
)
695 /* Page table entry*/
696 //printk("[EMI MPU] 2nd Entry pmd: %lx, *pmd = %lx\n", (unsigned long)(pmd), (unsigned long)pmd_val(*(pmd)));
698 addr_2nd_end
= addr_2nd
+ 0x100000;
699 for(; addr_2nd
<(addr_2nd_end
); addr_2nd
+=0x1000)
701 pte
= pte_offset_map(pmd
, addr_2nd
);
702 //printk("[EMI MPU] pmd: %x, pte: %x, *pte = %x, addr_2nd = 0x%x, addr_2nd_end = 0x%x\n", (unsigned long)(pmd), (unsigned long)(pte), (unsigned long)pte_val(*(pte)), addr_2nd, addr_2nd_end);
703 if(((unsigned long)v_addr
& PAGE_MASK
) == ((unsigned long)pte_val(*(pte
)) & PAGE_MASK
))
705 printk("[EMI MPU] Find page entry section at pte: %lx. violation address = 0x%x\n", (unsigned long)(pte
), v_addr
);
712 //printk("[EMI MPU] Section pmd: %x, addr = 0x%x\n", (unsigned long)(pmd), addr);
714 //if(v_addr>>20 == (unsigned long)pmd_val(*(pmd))>>20)
715 if(((unsigned long)pmd_val(*(pmd
)) & SECTION_MASK
) == ((unsigned long)v_addr
& SECTION_MASK
))
717 printk("[EMI MPU] Find page entry section at pmd: %lx. violation address = 0x%x\n", (unsigned long)(pmd
), v_addr
);
725 printk("[EMI MPU] ****** Can not find page table entry! violation address = 0x%x ******\n", v_addr
);
730 void emi_mpu_work_callback(struct work_struct
*work
)
732 printk("[EMI MPU] Enter EMI MPU workqueue!\n");
733 mtk_search_full_pgtab();
734 printk("[EMI MPU] Exit EMI MPU workqueue!\n");
737 static ssize_t
pgt_scan_show(struct device_driver
*driver
, char *buf
)
742 static ssize_t
pgt_scan_store(struct device_driver
*driver
, const char *buf
, size_t count
)
747 if (unlikely(sscanf(buf
, "%u", &value
) != 1))
752 ret
= queue_work(emi_mpu_workqueue
, &emi_mpu_work
);
755 printk(KERN_DEBUG
"[EMI MPU] submit workqueue failed, ret = %d\n", ret
);
761 DRIVER_ATTR(pgt_scan
, 0644, pgt_scan_show
, pgt_scan_store
);
763 static void emi_axi_set_chker(const unsigned int setting
)
767 value
= readl(IOMEM(EMI_CHKER
));
771 mt65xx_reg_sync_writel(value
, EMI_CHKER
);
774 static void emi_axi_set_master(const unsigned int setting
)
778 value
= readl(IOMEM(EMI_CHKER
));
779 value
&= ~(MASTER_ALL
<< AXI_NON_ALIGN_CHK_MST
);
780 value
|= (setting
& 0x7) << AXI_NON_ALIGN_CHK_MST
;
782 mt65xx_reg_sync_writel(value
, EMI_CHKER
);
785 static void emi_axi_dump_info(int aee_ke_en
)
787 int value
, master_ID
;
790 value
= readl(IOMEM(EMI_CHKER
));
791 master_ID
= (value
& 0x07FF0000) >> 16;
793 if (value
& 0x7FFF0000)
795 printk(KERN_CRIT
"AXI violation.\n");
796 printk(KERN_CRIT
"[EMI MPU AXI] Debug info start ----------------------------------------\n");
798 printk(KERN_CRIT
"EMI_CHKER = %x.\n", value
);
799 printk(KERN_CRIT
"Violation address is 0x%x.\n", readl(IOMEM(EMI_CHKER_ADR
)));
800 printk(KERN_CRIT
"Violation master ID is 0x%x.\n", master_ID
);
801 printk(KERN_CRIT
"Violation type is: AXI_ADR_CHK_EN(%d), AXI_LOCK_CHK_EN(%d), AXI_NON_ALIGN_CHK_EN(%d).\n",
802 (value
& (1 << AXI_ADR_CHK_EN
)) ? 1 : 0, (value
& (1 << AXI_LOCK_CHK_EN
)) ? 1 : 0, (value
& (1 << AXI_NON_ALIGN_CHK_EN
)) ? 1 : 0);
803 printk(KERN_CRIT
"%s violation.\n", (value
& AXI_VIO_WR
)? "Write": "Read");
805 printk(KERN_CRIT
"[EMI MPU AXI] Debug info end ----------------------------------------\n");
807 master_name
= __id2name(master_ID
);
808 #ifdef CONFIG_MTK_AEE_FEATURE
810 aee_kernel_exception("EMI MPU AXI", "AXI violation.\EMI_CHKER = 0x%x, module is %s.\n", value
, master_name
);
812 // clear AXI checker status
813 mt65xx_reg_sync_writel((1 << AXI_VIO_CLR
) | readl(IOMEM(EMI_CHKER
)), EMI_CHKER
);
817 static void emi_axi_vio_timer_func(unsigned long a
)
819 emi_axi_dump_info(1);
821 mod_timer(&emi_axi_vio_timer
, jiffies
+ AXI_VIO_MONITOR_TIME
);
824 static ssize_t
emi_axi_vio_show(struct device_driver
*driver
, char *buf
)
828 value
= readl(IOMEM(EMI_CHKER
));
830 emi_axi_dump_info(0);
832 return snprintf(buf
, PAGE_SIZE
, "AXI vio setting is: ADR_CHK_EN %s, LOCK_CHK_EN %s, NON_ALIGN_CHK_EN %s\n", (value
& (1 << AXI_ADR_CHK_EN
)) ? "ON" : "OFF",
833 (value
& (1 << AXI_LOCK_CHK_EN
)) ? "ON" : "OFF",
834 (value
& (1 << AXI_NON_ALIGN_CHK_EN
)) ? "ON" : "OFF");
837 ssize_t
emi_axi_vio_store(struct device_driver
*driver
, const char *buf
, size_t count
)
840 int cpu
= 0; //assign timer to CPU0 to avoid CPU plug-out and timer will be unavailable
842 value
= readl(IOMEM(EMI_CHKER
));
844 if (!strncmp(buf
, "ADR_CHK_ON", strlen("ADR_CHK_ON"))) {
845 emi_axi_set_chker(1 << AXI_ADR_CHK_EN
);
846 add_timer_on(&emi_axi_vio_timer
, cpu
);
847 } else if (!strncmp(buf
, "LOCK_CHK_ON", strlen("LOCK_CHK_ON"))) {
848 emi_axi_set_chker(1 << AXI_LOCK_CHK_EN
);
849 add_timer_on(&emi_axi_vio_timer
, cpu
);
850 } else if (!strncmp(buf
, "NON_ALIGN_CHK_ON", strlen("NON_ALIGN_CHK_ON"))) {
851 emi_axi_set_chker(1 << AXI_NON_ALIGN_CHK_EN
);
852 add_timer_on(&emi_axi_vio_timer
, cpu
);
853 } else if (!strncmp(buf
, "OFF", strlen("OFF"))) {
854 emi_axi_set_chker(0);
855 del_timer(&emi_axi_vio_timer
);
857 printk("invalid setting\n");
863 DRIVER_ATTR(emi_axi_vio
, 0644, emi_axi_vio_show
, emi_axi_vio_store
);
866 static int emi_mpu_panic_cb(struct notifier_block *this, unsigned long event, void *ptr)
868 emi_axi_dump_info(1);
873 #if 1 //#if !defined(USER_BUILD_KERNEL) || !defined(CONFIG_MT8127_EVB_BOARD)
874 static struct device_driver emi_mpu_ctrl
=
876 .name
= "emi_mpu_ctrl",
877 .bus
= &platform_bus_type
,
878 .owner
= THIS_MODULE
,
882 static struct notifier_block emi_mpu_blk = {
883 .notifier_call = emi_mpu_panic_cb,
886 static int __init
emi_mpu_mod_init(void)
888 #if 1 //#if !defined(USER_BUILD_KERNEL) || !defined(CONFIG_MT8127_EVB_BOARD)
892 printk(KERN_INFO
"Initialize EMI MPU.\n");
894 spin_lock_init(&emi_mpu_lock
);
896 __clear_emi_mpu_vio();
898 #ifndef CONFIG_MTK_IN_HOUSE_TEE_SUPPORT
899 //Set Device APC for EMI-MPU.
900 mt65xx_reg_sync_writel(readl(IOMEM(DEVAPC0_APC_CON
)) & (0xFFFFFFFF ^ (1<<2)), DEVAPC0_APC_CON
);
901 mt65xx_reg_sync_writel(readl(IOMEM(DEVAPC0_PD_APC_CON
)) & (0xFFFFFFFF ^ (1<<2)), DEVAPC0_PD_APC_CON
);
903 mt65xx_reg_sync_writel(ABORT_EMI_BUS_INTERFACE
, DEVAPC0_D0_VIO_STA_0
);
904 mt65xx_reg_sync_writel(readl(IOMEM(DEVAPC0_D0_VIO_MASK_0
)) & (0xFFFFFFFF ^ (1<<23)), DEVAPC0_D0_VIO_MASK_0
);
905 mt65xx_reg_sync_writel(ABORT_EMI
, DEVAPC0_D0_VIO_STA_3
);
906 mt65xx_reg_sync_writel(readl(IOMEM(DEVAPC0_D0_VIO_MASK_3
)) & (0xFFFFFFFF ^ (1<<13)), DEVAPC0_D0_VIO_MASK_3
);
910 * NoteXXX: Interrupts of vilation (including SPC in SMI, or EMI MPU)
911 * are triggered by the device APC.
912 * Need to share the interrupt with the SPC driver.
914 #if 1 //#ifndef CONFIG_MT8127_EVB_BOARD
915 ret
= request_irq(MT_APARM_DOMAIN_IRQ_ID
, (irq_handler_t
)mpu_violation_irq
, IRQF_TRIGGER_LOW
| IRQF_SHARED
, "mt_emi_mpu", &emi_mpu_ctrl
);
917 printk(KERN_CRIT
"Fail to request EMI_MPU interrupt. Error = %d.\n", ret
);
922 /* AXI violation monitor setting and timer function create */
923 mt65xx_reg_sync_writel((1 << AXI_VIO_CLR
) | readl(IOMEM(EMI_CHKER
)), EMI_CHKER
);
924 emi_axi_set_master(MASTER_ALL
);
925 init_timer(&emi_axi_vio_timer
);
926 emi_axi_vio_timer
.expires
= jiffies
+ AXI_VIO_MONITOR_TIME
;
927 emi_axi_vio_timer
.function
= &emi_axi_vio_timer_func
;
928 emi_axi_vio_timer
.data
= ((unsigned long) 0 );
930 #if !defined(USER_BUILD_KERNEL)
931 /* Enable AXI 4KB boundary violation monitor timer */
932 emi_axi_set_chker(1 << AXI_ADR_CHK_EN
);
933 //add_timer_on(&emi_axi_vio_timer, 0);
935 /* register driver and create sysfs files */
936 ret
= driver_register(&emi_mpu_ctrl
);
938 printk(KERN_CRIT
"Fail to register EMI_MPU driver.\n");
940 ret
= driver_create_file(&emi_mpu_ctrl
, &driver_attr_mpu_config
);
941 ret
= driver_create_file(&emi_mpu_ctrl
, &driver_attr_emi_axi_vio
);
942 ret
= driver_create_file(&emi_mpu_ctrl
, &driver_attr_pgt_scan
);
944 printk(KERN_CRIT
"Fail to create AXI violation monitor sysfs file.\n");
948 //atomic_notifier_chain_register(&panic_notifier_list, &emi_mpu_blk);
950 /* Create a workqueue to search pagetable entry */
951 emi_mpu_workqueue
= create_singlethread_workqueue("emi_mpu");
952 INIT_WORK(&emi_mpu_work
, emi_mpu_work_callback
);
954 //emi_mpu_set_region_protection(0x9c000000,
955 // 0x9d7fffff, /*MD_IMG_REGION_LEN*/
957 // SET_ACCESS_PERMISSON(SEC_R_NSEC_R, SEC_R_NSEC_R, SEC_R_NSEC_R, SEC_R_NSEC_R));
962 static void __exit
emi_mpu_mod_exit(void)
966 module_init(emi_mpu_mod_init
);
967 module_exit(emi_mpu_mod_exit
);
969 EXPORT_SYMBOL(emi_mpu_set_region_protection
);
970 //EXPORT_SYMBOL(start_mm_mau_protect);