| // SPDX-License-Identifier: GPL-2.0+ | |
| /* | |
| * Copyright 2015 Freescale Semiconductor, Inc. | |
| */ | |
| #include <config.h> | |
| #include <fsl_sec_mon.h> | |
| #include <linux/delay.h> | |
| static u32 get_sec_mon_state(void) | |
| { | |
| struct ccsr_sec_mon_regs *sec_mon_regs = (void *) | |
| (CFG_SYS_SEC_MON_ADDR); | |
| return sec_mon_in32(&sec_mon_regs->hp_stat) & HPSR_SSM_ST_MASK; | |
| } | |
| static int set_sec_mon_state_non_sec(void) | |
| { | |
| u32 sts; | |
| int timeout = 10; | |
| struct ccsr_sec_mon_regs *sec_mon_regs = (void *) | |
| (CFG_SYS_SEC_MON_ADDR); | |
| sts = get_sec_mon_state(); | |
| switch (sts) { | |
| /* | |
| * If initial state is check or Non-Secure, then set the Software | |
| * Security Violation Bit and transition to Non-Secure State. | |
| */ | |
| case HPSR_SSM_ST_CHECK: | |
| printf("SEC_MON state transitioning to Non Secure.\n"); | |
| sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SW_SV); | |
| /* polling loop till SEC_MON is in Non Secure state */ | |
| while (timeout) { | |
| sts = get_sec_mon_state(); | |
| 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; | |
| /* | |
| * If initial state is Trusted, Secure or Soft-Fail, then first set | |
| * the Software Security Violation Bit and transition to Soft-Fail | |
| * State. | |
| */ | |
| case HPSR_SSM_ST_TRUST: | |
| case HPSR_SSM_ST_SECURE: | |
| 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_SV); | |
| /* polling loop till SEC_MON is in Soft-Fail state */ | |
| while (timeout) { | |
| sts = get_sec_mon_state(); | |
| 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; | |
| /* | |
| * If SSM Soft Fail to Non-Secure State Transition | |
| * disable is not set, then set SSM_ST bit and | |
| * transition to Non-Secure State. | |
| */ | |
| if ((sec_mon_in32(&sec_mon_regs->hp_com) & | |
| HPCOMR_SSM_SFNS_DIS) == 0) { | |
| printf("SEC_MON state transitioning to Non Secure.\n"); | |
| sec_mon_setbits32(&sec_mon_regs->hp_com, HPCOMR_SSM_ST); | |
| /* polling loop till SEC_MON is in Non Secure*/ | |
| while (timeout) { | |
| sts = get_sec_mon_state(); | |
| 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; | |
| default: | |
| printf("SEC_MON already in Non Secure state.\n"); | |
| return 0; | |
| } | |
| return 0; | |
| } | |
| static int set_sec_mon_state_soft_fail(void) | |
| { | |
| u32 sts; | |
| int timeout = 10; | |
| struct ccsr_sec_mon_regs *sec_mon_regs = (void *) | |
| (CFG_SYS_SEC_MON_ADDR); | |
| 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 (timeout) { | |
| sts = get_sec_mon_state(); | |
| 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; | |
| } | |
| return 0; | |
| } | |
| int set_sec_mon_state(u32 state) | |
| { | |
| int ret = -1; | |
| switch (state) { | |
| case HPSR_SSM_ST_NON_SECURE: | |
| ret = set_sec_mon_state_non_sec(); | |
| break; | |
| case HPSR_SSM_ST_SOFT_FAIL: | |
| ret = set_sec_mon_state_soft_fail(); | |
| break; | |
| default: | |
| printf("SEC_MON state transition not supported.\n"); | |
| return 0; | |
| } | |
| return ret; | |
| } |