blob: 46dc4a1be0b8b7b446c5806dfe9121dfb373153b [file] [log] [blame]
/*
* linux/drivers/marvell/mmp-debug.c
*
* Author: Neil Zhang <zhangwm@marvell.com>
* Copyright: (C) 2013 Marvell International Ltd.
*
* 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.
*/
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/init.h>
#include <linux/reboot.h>
#include <linux/kexec.h>
#include <linux/signal.h>
#include <linux/features.h>
#include <soc/asr/regs-addr.h>
#include <asm/cacheflush.h>
#include <asm/system_misc.h>
#ifdef CONFIG_CPU_ASR1901
#define FAB_TIMEOUT_CTRL 0x230
#define FAB_TIMEOUT_STATUS0 0x264
#define FAB_TIMEOUT_STATUS1 0x268
#define FAB_TIMEOUT_ID 0x260
#else
#define FAB_TIMEOUT_CTRL 0x60
#define FAB_TIMEOUT_STATUS0 0x68
#define FAB_TIMEOUT_STATUS1 0x70
#define FAB_TIMEOUT_ID 0x78
#endif
static void __iomem *squ_base, *apmu_base;
static u32 fab_timeout_write_addr, fab_timeout_read_addr;
static int mmp_axi_timeout(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
u32 tmp;
(void) addr;
(void) fsr;
(void) regs;
tmp = readl_relaxed(squ_base + FAB_TIMEOUT_STATUS0);
fab_timeout_write_addr = tmp & 0xfffffffc;
tmp = readl_relaxed(squ_base + FAB_TIMEOUT_STATUS1);
fab_timeout_read_addr = tmp & 0xfffffffc;
/* Return For those not caused by AXI timeout */
if (!fab_timeout_write_addr && !fab_timeout_read_addr)
return 1;
pr_info("********** mmp_axi_timeout **********\n");
pr_info("write_addr=0x%x read_addr=0x%x",
fab_timeout_write_addr, fab_timeout_read_addr);
pr_info("FAB_TIMEOUT_ID=0x%x\n",
readl_relaxed(squ_base + FAB_TIMEOUT_ID));
pr_info("FAB_TIMEOUT_STATUS0=0x%x\n",
readl_relaxed(squ_base + FAB_TIMEOUT_STATUS0));
pr_info("FAB_TIMEOUT_STATUS1=0x%x\n",
readl_relaxed(squ_base + FAB_TIMEOUT_STATUS1));
pr_info("PMU_SDH0_CLK_RES_CTRL=0x%x\n",
readl_relaxed(apmu_base + 0x54));
pr_info("PMU_SDH1_CLK_RES_CTRL=0x%x\n",
readl_relaxed(apmu_base + 0x58));
pr_info("PMU_QSPI_CLK_RES_CTRL=0x%x\n",
readl_relaxed(apmu_base + 0x60));
#ifdef CONFIG_CPU_ASR1901
pr_info("XGMAC_CLK_RST_CTRL=0x%x\n",
readl_relaxed(apmu_base + 0x3d4));
#else
pr_info("EMAC_CLK_RST_CTRL=0x%x\n",
readl_relaxed(apmu_base + 0x160));
#endif
pr_info("*************************************\n");
/* return 1 to trigger ramdump later */
return 1;
}
static int __init mmp_debug_init(void)
{
struct device_node *node;
u32 tmp;
node = of_find_compatible_node(NULL, NULL, "mrvl,mmp-debug");
if (!node) {
pr_info("This platform doesn't support debug feature!\n");
return 0;
}
squ_base = of_iomap(node, 0);
apmu_base = regs_addr_get_va(REGS_ADDR_APMU);
pr_info("axi facbric monitor last save info:\n");
pr_info("FAB_TIMEOUT_ID=0x%x\n",
readl_relaxed(squ_base + FAB_TIMEOUT_ID));
pr_info("FAB_TIMEOUT_STATUS0=0x%x\n",
readl_relaxed(squ_base + FAB_TIMEOUT_STATUS0));
pr_info("FAB_TIMEOUT_STATUS1=0x%x\n",
readl_relaxed(squ_base + FAB_TIMEOUT_STATUS1));
/* clear last saved information */
tmp = readl_relaxed(squ_base + FAB_TIMEOUT_CTRL);
tmp |= 1 << 27;
writel_relaxed(tmp, squ_base + FAB_TIMEOUT_CTRL);
/* reset axi fabric monitor */
tmp = readl_relaxed(squ_base + FAB_TIMEOUT_CTRL);
tmp &= ~(1 << 28);
writel_relaxed(tmp, squ_base + FAB_TIMEOUT_CTRL);
/* configure to data abort mode */
tmp = readl_relaxed(squ_base + FAB_TIMEOUT_CTRL);
tmp &= ~(1 << 31);
tmp |= 1 << 30;
tmp |= 1 << 29; /* mask timeout interrupt */
tmp |= 1 << 28;
tmp &= ~(1 << 27);
#ifdef CONFIG_CPU_ASR1901
tmp &= ~(1 << 24);
#endif
writel_relaxed(tmp, squ_base + FAB_TIMEOUT_CTRL);
pr_info("enable mmp axi facbric monitor, FAB_TIMEOUT_CTRL=0x%x\n",
readl_relaxed(squ_base + FAB_TIMEOUT_CTRL));
/* Register debug fault handler. */
#ifdef CONFIG_ARM
hook_fault_code(0x8, mmp_axi_timeout, SIGBUS,
0, "external abort on non-linefetch");
hook_fault_code(0xc, mmp_axi_timeout, SIGBUS,
0, "external abort on translation");
hook_fault_code(0xe, mmp_axi_timeout, SIGBUS,
0, "external abort on translation");
hook_fault_code(0x16, mmp_axi_timeout, SIGBUS,
BUS_OBJERR, "imprecise external abort");
#endif
#ifdef CONFIG_ARM64
hook_fault_code(0x10, mmp_axi_timeout, SIGBUS,
0, "synchronous external abort");
hook_fault_code(0x11, mmp_axi_timeout, SIGBUS,
0, "asynchronous external abort");
#endif
return 0;
}
arch_initcall(mmp_debug_init);