diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0df25c331f..36a8f0d098 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -53,3 +53,11 @@ config DM_CROS_EC but otherwise makes few changes. Since cros_ec also supports LPC (which doesn't support driver model yet), a full conversion is not yet possible. + +config CONFIG_FSL_SEC_MON + bool "Enable FSL SEC_MON Driver" + help + Freescale Security Monitor block is responsible for monitoring + system states. + Security Monitor can be transitioned on any security failures, + like software violations or hardware security violations. diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a34972df4e..6028cd43fb 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_SMSC_LPC47M) += smsc_lpc47m.o obj-$(CONFIG_STATUS_LED) += status_led.o obj-$(CONFIG_TWL4030_LED) += twl4030_led.o obj-$(CONFIG_FSL_IFC) += fsl_ifc.o +obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o diff --git a/drivers/misc/fsl_sec_mon.c b/drivers/misc/fsl_sec_mon.c new file mode 100644 index 0000000000..d482a7db9c --- /dev/null +++ b/drivers/misc/fsl_sec_mon.c @@ -0,0 +1,146 @@ +/* + * Copyright 2015 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include +#include + +int change_sec_mon_state(u32 initial_state, u32 final_state) +{ + struct ccsr_sec_mon_regs *sec_mon_regs = (void *) + (CONFIG_SYS_SEC_MON_ADDR); + u32 sts = sec_mon_in32(&sec_mon_regs->hp_stat); + int timeout = 10; + + if ((sts & HPSR_SSM_ST_MASK) != initial_state) + return -1; + + if (initial_state == HPSR_SSM_ST_TRUST) { + switch (final_state) { + case HPSR_SSM_ST_NON_SECURE: + printf("SEC_MON state transitioning to Soft Fail.\n"); + sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_SV); + + /* + * poll till SEC_MON is in + * Soft Fail state + */ + while (((sts & HPSR_SSM_ST_MASK) != + HPSR_SSM_ST_SOFT_FAIL)) { + while (timeout) { + sts = sec_mon_in32 + (&sec_mon_regs->hp_stat); + + if ((sts & HPSR_SSM_ST_MASK) == + HPSR_SSM_ST_SOFT_FAIL) + break; + + udelay(10); + timeout--; + } + } + + if (timeout == 0) { + printf("SEC_MON state transition timeout.\n"); + return -1; + } + + timeout = 10; + + printf("SEC_MON state transitioning to Non Secure.\n"); + sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SSM_ST); + + /* + * poll till SEC_MON is in + * Non Secure state + */ + while (((sts & HPSR_SSM_ST_MASK) != + HPSR_SSM_ST_NON_SECURE)) { + while (timeout) { + sts = sec_mon_in32 + (&sec_mon_regs->hp_stat); + + if ((sts & HPSR_SSM_ST_MASK) == + HPSR_SSM_ST_NON_SECURE) + break; + + udelay(10); + timeout--; + } + } + + if (timeout == 0) { + printf("SEC_MON state transition timeout.\n"); + return -1; + } + break; + case HPSR_SSM_ST_SOFT_FAIL: + printf("SEC_MON state transitioning to Soft Fail.\n"); + sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_FSV); + + /* + * polling loop till SEC_MON is in + * Soft Fail state + */ + while (((sts & HPSR_SSM_ST_MASK) != + HPSR_SSM_ST_SOFT_FAIL)) { + while (timeout) { + sts = sec_mon_in32 + (&sec_mon_regs->hp_stat); + + if ((sts & HPSR_SSM_ST_MASK) == + HPSR_SSM_ST_SOFT_FAIL) + break; + + udelay(10); + timeout--; + } + } + + if (timeout == 0) { + printf("SEC_MON state transition timeout.\n"); + return -1; + } + break; + default: + return -1; + } + } else if (initial_state == HPSR_SSM_ST_NON_SECURE) { + switch (final_state) { + case HPSR_SSM_ST_SOFT_FAIL: + printf("SEC_MON state transitioning to Soft Fail.\n"); + sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_FSV); + + /* + * polling loop till SEC_MON is in + * Soft Fail state + */ + while (((sts & HPSR_SSM_ST_MASK) != + HPSR_SSM_ST_SOFT_FAIL)) { + while (timeout) { + sts = sec_mon_in32 + (&sec_mon_regs->hp_stat); + + if ((sts & HPSR_SSM_ST_MASK) == + HPSR_SSM_ST_SOFT_FAIL) + break; + + udelay(10); + timeout--; + } + } + + if (timeout == 0) { + printf("SEC_MON state transition timeout.\n"); + return -1; + } + break; + default: + return -1; + } + } + + return 0; +} diff --git a/include/fsl_sec_mon.h b/include/fsl_sec_mon.h new file mode 100644 index 0000000000..b6794cefcc --- /dev/null +++ b/include/fsl_sec_mon.h @@ -0,0 +1,58 @@ +/* + * Common internal memory map for some Freescale SoCs + * + * Copyright 2015 Freescale Semiconductor, Inc. + * SPDX-License-Identifier: GPL-2.0+ + */ + +#ifndef __FSL_SEC_MON_H +#define __FSL_SEC_MON_H + +#include +#include + +#ifdef CONFIG_SYS_FSL_SEC_MON_LE +#define sec_mon_in32(a) in_le32(a) +#define sec_mon_out32(a, v) out_le32(a, v) +#define sec_mon_in16(a) in_le16(a) +#define sec_mon_clrbits32 clrbits_le32 +#define sec_mon_setbits32 setbits_le32 +#elif defined(CONFIG_SYS_FSL_SEC_MON_BE) +#define sec_mon_in32(a) in_be32(a) +#define sec_mon_out32(a, v) out_be32(a, v) +#define sec_mon_in16(a) in_be16(a) +#define sec_mon_clrbits32 clrbits_be32 +#define sec_mon_setbits32 setbits_be32 +#else +#error Neither CONFIG_SYS_FSL_SEC_MON_LE nor CONFIG_SYS_FSL_SEC_MON_BE defined +#endif + +struct ccsr_sec_mon_regs { + u8 reserved0[0x04]; + u32 hp_com; /* 0x04 SEC_MON_HP Command Register */ + u8 reserved2[0x0c]; + u32 hp_stat; /* 0x08 SEC_MON_HP Status Register */ +}; + +#define HPCOMR_SW_SV 0x100 /* Security Violation bit */ +#define HPCOMR_SW_FSV 0x200 /* Fatal Security Violation bit */ +#define HPCOMR_SSM_ST 0x1 /* SSM_ST field in SEC_MON command */ +#define HPSR_SSM_ST_CHECK 0x900 /* SEC_MON is in check state */ +#define HPSR_SSM_ST_NON_SECURE 0xb00 /* SEC_MON is in non secure state */ +#define HPSR_SSM_ST_TRUST 0xd00 /* SEC_MON is in trusted state */ +#define HPSR_SSM_ST_SOFT_FAIL 0x300 /* SEC_MON is in soft fail state */ +#define HPSR_SSM_ST_MASK 0xf00 /* Mask for SSM_ST field */ + +/* + * SEC_MON read. This specifies the possible reads + * from the SEC_MON + */ +enum { + SEC_MON_SSM_ST, + SEC_MON_SW_FSV, + SEC_MON_SW_SV, +}; + +int change_sec_mon_state(uint32_t initial_state, uint32_t final_state); + +#endif /* __FSL_SEC_MON_H */