| /* |
| * ../vendor/amlogic/common/gpu/utgard/platform/meson_m400/mali_fix.c |
| * |
| * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/types.h> |
| #include <linux/timer.h> |
| #include <asm/io.h> |
| #include <linux/ioport.h> |
| #include <linux/dma-mapping.h> |
| |
| #include <linux/module.h> |
| |
| #include <mach/am_regs.h> |
| #include <mach/clock.h> |
| #include <linux/io.h> |
| #include <mach/io.h> |
| #include <plat/io.h> |
| #include <asm/io.h> |
| |
| #include "mali_kernel_common.h" |
| #include "mali_osk.h" |
| #include "mali_platform.h" |
| #include "mali_fix.h" |
| |
| #define MALI_MM1_REG_ADDR 0xd0064000 |
| #define MALI_MMU_REGISTER_INT_STATUS 0x0008 |
| #define MALI_MM2_REG_ADDR 0xd0065000 |
| #define MALI_MMU_REGISTER_INT_STATUS 0x0008 |
| #define MALI_MM_REG_SIZE 0x1000 |
| |
| #define READ_MALI_MMU1_REG(r) (ioread32(((u8*)mali_mm1_regs) + r)) |
| #define READ_MALI_MMU2_REG(r) (ioread32(((u8*)mali_mm2_regs) + r)) |
| |
| extern int mali_PP0_int_cnt(void); |
| extern int mali_PP1_int_cnt(void); |
| |
| #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 |
| static ulong * mali_mm1_regs = NULL; |
| static ulong * mali_mm2_regs = NULL; |
| static struct timer_list timer; |
| |
| static u32 mali_pp1_int_count = 0; |
| static u32 mali_pp2_int_count = 0; |
| static u32 mali_pp1_mmu_int_count = 0; |
| static u32 mali_pp2_mmu_int_count = 0; |
| static u32 mali_mmu_int_process_state[2]; |
| |
| static void timer_callback(ulong data) |
| { |
| unsigned long mali_flags; |
| |
| mali_pp1_int_count = mali_PP0_int_cnt(); |
| mali_pp2_int_count = mali_PP1_int_cnt(); |
| |
| /* lock mali_clock_gating when access Mali registers */ |
| mali_flags = mali_clock_gating_lock(); |
| |
| if (readl((u32 *)P_HHI_MALI_CLK_CNTL) & 0x100) { |
| /* polling for PP1 MMU interrupt */ |
| if (mali_mmu_int_process_state[0] == MMU_INT_NONE) { |
| if (READ_MALI_MMU1_REG(MALI_MMU_REGISTER_INT_STATUS) != 0) { |
| mali_pp1_mmu_int_count++; |
| MALI_DEBUG_PRINT(3, ("Mali MMU: core0 page fault emit \n")); |
| mali_mmu_int_process_state[0] = MMU_INT_HIT; |
| __raw_writel(1, (volatile void *)P_ISA_TIMERC); |
| } |
| } |
| |
| /* polling for PP2 MMU interrupt */ |
| if (mali_mmu_int_process_state[1] == MMU_INT_NONE) { |
| if (READ_MALI_MMU2_REG(MALI_MMU_REGISTER_INT_STATUS) != 0) { |
| mali_pp2_mmu_int_count++; |
| MALI_DEBUG_PRINT(3, ("Mali MMU: core1 page fault emit \n")); |
| mali_mmu_int_process_state[1] = MMU_INT_HIT; |
| __raw_writel(1, (volatile void *)P_ISA_TIMERC); |
| } |
| } |
| } |
| |
| mali_clock_gating_unlock(mali_flags); |
| |
| timer.expires = jiffies + HZ/100; |
| |
| add_timer(&timer); |
| } |
| |
| void malifix_set_mmu_int_process_state(int index, int state) |
| { |
| if (index < 2) |
| mali_mmu_int_process_state[index] = state; |
| } |
| |
| int malifix_get_mmu_int_process_state(int index) |
| { |
| if (index < 2) |
| return mali_mmu_int_process_state[index]; |
| return 0; |
| } |
| #endif |
| |
| void malifix_init(void) |
| { |
| #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 |
| if (!mali_meson_is_revb()) |
| return; |
| |
| if ((mali_mm1_regs) && (mali_mm2_regs)) return; |
| mali_mmu_int_process_state[0] = 0; |
| mali_mmu_int_process_state[1] = 0; |
| |
| /* set up Timer C as a 1uS one-shot timer */ |
| aml_clr_reg32_mask(P_ISA_TIMER_MUX, (1<<18)|(1<<14)|(3<<4)); |
| aml_set_reg32_mask(P_ISA_TIMER_MUX, (1<<18)|(0<<14)|(0<<4)); |
| |
| setup_timer(&timer, timer_callback, 0); |
| |
| mali_mm1_regs = (ulong *)ioremap_nocache(MALI_MM1_REG_ADDR, MALI_MM_REG_SIZE); |
| if (mali_mm1_regs) |
| printk("Mali pp1 MMU register mapped at %p...\n", mali_mm1_regs); |
| |
| mali_mm2_regs = (ulong *)ioremap_nocache(MALI_MM2_REG_ADDR, MALI_MM_REG_SIZE); |
| if (mali_mm2_regs) |
| printk("Mali pp2 MMU register mapped at %p...\n", mali_mm2_regs); |
| |
| if ((mali_mm1_regs != NULL) && (mali_mm2_regs != NULL)) |
| mod_timer(&timer, jiffies + HZ/100); |
| #endif |
| } |
| |
| void malifix_exit(void) |
| { |
| #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 |
| if (!mali_meson_is_revb()) |
| return; |
| |
| del_timer(&timer); |
| |
| if (mali_mm1_regs != NULL) |
| iounmap(mali_mm1_regs); |
| mali_mm1_regs = NULL; |
| |
| if (mali_mm2_regs != NULL) |
| iounmap(mali_mm2_regs); |
| mali_mm2_regs = NULL; |
| |
| #endif |
| return; |
| } |
| |
| #if MESON_CPU_TYPE == MESON_CPU_TYPE_MESON6 |
| module_param(mali_pp1_int_count, uint, 0664); |
| MODULE_PARM_DESC(mali_pp1_int_count, "Mali PP1 interrupt count\n"); |
| |
| module_param(mali_pp2_int_count, uint, 0664); |
| MODULE_PARM_DESC(mali_pp2_int_count, "Mali PP1 interrupt count\n"); |
| |
| module_param(mali_pp1_mmu_int_count, uint, 0664); |
| MODULE_PARM_DESC(mali_pp1_mmu_int_count, "Mali PP1 mmu interrupt count\n"); |
| |
| module_param(mali_pp2_mmu_int_count, uint, 0664); |
| MODULE_PARM_DESC(mali_pp2_mmu_int_count, "Mali PP2 mmu interrupt count\n"); |
| #endif |
| |
| MODULE_DESCRIPTION("AMLOGIC mali fix driver"); |
| MODULE_LICENSE("GPL"); |
| MODULE_AUTHOR("Tim Yao <timyao@amlogic.com>"); |