123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449 |
- /*
- * Copyright (C) 2017-2020 Alibaba Group Holding Limited
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
- #include <common.h>
- #include <asm/io.h>
- #include <asm/types.h>
- #include <thead/clock_config.h>
- #include <linux/bitops.h>
- #include <asm/arch-thead/light-iopmp.h>
- #include <asm/arch-thead/light-plic.h>
- #define LIGHT_TEE_SYSREG_BASE ((void __iomem*)0xffff200000)
- #define REG_SECURITY_ERR_3 (LIGHT_TEE_SYSREG_BASE + 0x30)
- /* id: 0~8 */
- #define DS_C910_BASE(id) (0xffffc57000 + (id) * 0x40)
- #define DS_APB_BASE(id) (0xffff270000 + ((id) - 4) * 0x1000)
- #define DS_BASE(id) (((id) > 3) ? (DS_APB_BASE(id)) : (DS_C910_BASE(id)))
- #define REG_HW_VERSION(id) ((void __iomem *)DS_BASE(id) + 0x00) //RO
- #define REG_SENSOR_ALARM(id) ((void __iomem *)DS_BASE(id) + 0x04) //RO
- #define REG_HEALTH_TEST_ALARM(id) ((void __iomem *)DS_BASE(id) + 0x08) //RO
- #define REG_HEALTH_TEST_STATUS(id) ((void __iomem *)DS_BASE(id) + 0x0C) //RO
- #define REG_CONTROL(id) ((void __iomem *)DS_BASE(id) + 0x10) //WO
- #define REG_IRQ_STATUS(id) ((void __iomem *)DS_BASE(id) + 0x14) //RO
- #define REG_IRQ_CLEAR(id) ((void __iomem *)DS_BASE(id) + 0x18) //WO
- #define REG_IRQ_CONFIG(id) ((void __iomem *)DS_BASE(id) + 0x1C) //RW
- #define REG_STATUS_DSX(id, x) ((void __iomem *)DS_BASE(id) + 0x20 + 0x04 * x) //RO
- #define LIGHT_SEC_IRQ_NUM 91
- #define MAX_DIGITAL_SENSOR_NUM 9
- #define MAX_HW_MACRO_NUM_PER_DS 16
- #define DS_HW_MACRO_TL_MASK 0xffff
- #define DS_INVALID_MACRO_ID MAX_HW_MACRO_NUM_PER_DS
- #define DS_1_ERR BIT(16) //digital_sensor_C910_0 ~ digital_sensor_C910_3
- #define DS_3_ERR BIT(18) //digital_sensor_apb_3
- #define DS_4_ERR BIT(19) //digital_sensor_apb_4
- #define DS_5_ERR BIT(20) //digital_sensor_apb_5
- #define DS_6_ERR BIT(21) //digital_sensor_apb_6
- #define DS_7_ERR BIT(22) //digital_sensor_apb_7
- #define DS_ERR (DS_1_ERR | DS_3_ERR | DS_4_ERR | DS_5_ERR | DS_6_ERR | DS_7_ERR)
- #define CFG_DS_CPU_THREAT_LEVEL 0
- #define CFG_APB0_THREAT_LEVEL 0
- #define CFG_APB1_THREAT_LEVEL 0
- #define AONSYS_RSTGEN_BASE ((void __iomem *)0xFFFFF44000UL)
- #define REG_SYS_RST_CFG (AONSYS_RSTGEN_BASE + 0x10)
- #define SW_SYS_RST_REQ (1 << 0)
- #define REG_RST_REQ_EN_0 (AONSYS_RSTGEN_BASE + 0x140)
- #define SW_GLB_RST_EN (1 << 0)
- struct ds_data {
- int id;
- u32 hw_macro_num;
- };
- struct ds_data ds_array[MAX_DIGITAL_SENSOR_NUM] = {
- {0, 4}, //digital_sensor_C910_0
- {1, 4}, //digital_sensor_C910_1
- {2, 4}, //digital_sensor_C910_2
- {3, 4}, //digital_sensor_C910_3
- {4, 16}, //digital_sensor_apb_3
- {5, 11}, //digital_sensor_apb_4
- {6, 4}, //digital_sensor_apb_5
- {7, 16}, //digital_sensor_apb_6
- {8, 8}, //digital_sensor_apb_7
- };
- static void system_reset(void)
- {
- u32 data = readl(REG_RST_REQ_EN_0);
- /* global reset enable */
- data |= SW_GLB_RST_EN;
- writel(data, REG_RST_REQ_EN_0);
- /* global reset request */
- writel(SW_SYS_RST_REQ, REG_SYS_RST_CFG);
- mdelay(1000);
- }
- static u32 ds_hw_macro_threat_level_get(int ds_id, u32 macro_id)
- {
- return readl(REG_STATUS_DSX(ds_id, macro_id)) & DS_HW_MACRO_TL_MASK;
- }
- static __maybe_unused int ds_health_test_done_status(int ds_id, u32 macro_id)
- {
- return readl(REG_HEALTH_TEST_STATUS(ds_id)) & (1 << macro_id) ? 1 : 0;
- }
- static __maybe_unused int ds_health_test_alarm_status(int ds_id, u32 macro_id)
- {
- return readl(REG_HEALTH_TEST_ALARM(ds_id)) & (1 << macro_id) ? 1 : 0;
- }
- static __maybe_unused bool ds_sensor_alarm_event_hw_macro_get(int ds_id, u32 *event_macro)
- {
- u32 alarm_status = readl(REG_SENSOR_ALARM(ds_id));
- int num = ds_array[ds_id].hw_macro_num;
- int s_alarm_bit = 0, j = 0;
- bool sensor_alarm_event_occured = false;
- for (int i = 0; i < num; i++) {
- s_alarm_bit = 1 << i;
- if (alarm_status & s_alarm_bit) {
- event_macro[j] = i;
- j++;
- sensor_alarm_event_occured = true;
- }
- }
- return sensor_alarm_event_occured;
- }
- static __maybe_unused bool ds_health_alarm_event_hw_macro_get(int ds_id, u32 *event_macro)
- {
- u32 h_alarm_status = readl(REG_HEALTH_TEST_ALARM(ds_id));
- int num = ds_array[ds_id].hw_macro_num;
- int h_alarm_bit = 0, j = 0;
- bool health_alarm_event_occured = false;
- for (int i = 0; i < num; i++) {
- h_alarm_bit = 1 << i;
- if (h_alarm_status & h_alarm_bit) {
- event_macro[j] = i;
- j++;
- health_alarm_event_occured = true;
- }
- }
- return health_alarm_event_occured;
- }
- static bool ds_sensor_irq_hw_macro_get(int ds_id, u32 *irq_macro)
- {
- u32 irq_status = readl(REG_IRQ_STATUS(ds_id));
- int num = ds_array[ds_id].hw_macro_num;
- int s_alarm_bit = 0, j = 0;
- bool sensor_alarm_irq_occured = false;
- for (int i = 0; i < num; i++) {
- s_alarm_bit = 1 << ((i << 1) + 1);
- if (irq_status & s_alarm_bit) {
- irq_macro[j] = i;
- debug("[%s,%d]irq_macro[%d] = %d\n", __func__, __LINE__,
- j, irq_macro[j]);
- j++;
- sensor_alarm_irq_occured = true;
- }
- }
- debug("[%s,%d] sensor_alarm_irq_occured = %d\n", __func__, __LINE__,
- sensor_alarm_irq_occured);
- return sensor_alarm_irq_occured;
- }
- static __maybe_unused bool ds_health_irq_hw_macro_get(int ds_id, u32 *irq_macro)
- {
- u32 irq_status = readl(REG_IRQ_STATUS(ds_id));
- int num = ds_array[ds_id].hw_macro_num;
- int h_alarm_bit = 0, j = 0;
- bool health_alarm_irq_occured = false;
- for (int i = 0; i < num; i++) {
- h_alarm_bit = 1 << (i << 1);
- if (irq_status & h_alarm_bit) {
- irq_macro[j] = i;
- j++;
- health_alarm_irq_occured = true;
- }
- }
- return health_alarm_irq_occured;
- }
- static void ds_sensor_irq_clear(int ds_id, u32 macro_id)
- {
- int s_alarm_bit = 1 << ((macro_id << 1) + 1);
- debug("[%s,%d]reg: 0x%lx, s_alarm_bit = 0x%x\n", __func__, __LINE__,
- (unsigned long)REG_IRQ_CLEAR(ds_id), s_alarm_bit);
- writel(s_alarm_bit, REG_IRQ_CLEAR(ds_id));
- }
- static __maybe_unused void ds_health_irq_clear(int ds_id, u32 macro_id)
- {
- int h_alarm_bit = 1 << (macro_id << 1);
- writel(h_alarm_bit, REG_IRQ_CLEAR(ds_id));
- }
- static void ds_hw_macro_sensor_alarm_endisable(int ds_id, u32 macro_id, bool en)
- {
- int s_alarm_bit = 1 << ((macro_id << 1) + 1);
- u32 bitmap = readl(REG_IRQ_CONFIG(ds_id));
- if (en)
- bitmap |= s_alarm_bit;
- else
- bitmap &= ~s_alarm_bit;
- writel(bitmap, REG_IRQ_CONFIG(ds_id));
- }
- static __maybe_unused void ds_hw_macro_health_alarm_endisable(int ds_id, u32 macro_id, bool en)
- {
- int h_alarm_bit = 1 << (macro_id << 1);
- u32 bitmap = readl(REG_IRQ_CONFIG(ds_id));
- if (en)
- bitmap |= h_alarm_bit;
- else
- bitmap &= ~h_alarm_bit;
- writel(bitmap, REG_IRQ_CONFIG(ds_id));
- }
- static void ds_hw_macro_rearm(int ds_id, u32 macro_id, int macro_size)
- {
- int rearm_bit = 1 << (macro_id + macro_size);
- debug("[%s,%d]rearm_bit = 0x%x\n", __func__, __LINE__, rearm_bit);
- writel(rearm_bit, REG_CONTROL(ds_id));
- }
- static __maybe_unused void ds_hw_macro_health_test_start(int ds_id, u32 macro_id)
- {
- int start_bit = 1 << macro_id;
- writel(start_bit, REG_CONTROL(ds_id));
- }
- static void light_sec_irq_handler(void)
- {
- u32 id, i, j = 0, t = 0, size;
- u32 tl;
- u32 irq_macro[MAX_HW_MACRO_NUM_PER_DS] = {0};
- u32 apb_ds[8] = {0};
- u32 status = readl(REG_SECURITY_ERR_3);
- if (!status)
- return;
- if (!(status & DS_ERR)) {
- printf("Unexpected security interrupt but not ditital sensor alarm occured\n");
- return; //drop other security interrupts, how to clear ?
- }
- if (status & DS_1_ERR) {
- printf("C910 cpu digital sensor detect error event\n");
- for (id = 0; id < 4; id++) {
- for (i = 0; i < ARRAY_SIZE(irq_macro); i++)
- irq_macro[i] = DS_INVALID_MACRO_ID;
- if (!ds_sensor_irq_hw_macro_get(id, irq_macro))
- continue;
- size = ds_array[id].hw_macro_num;
- i = 0;
- while (i < MAX_HW_MACRO_NUM_PER_DS && irq_macro[i] != DS_INVALID_MACRO_ID) {
- tl = ds_hw_macro_threat_level_get(id, irq_macro[i]);
- printf("DS%d-MACRO%d Threat Level: 0x%x\n", id, irq_macro[i], tl);
- if (tl >= CFG_DS_CPU_THREAT_LEVEL) {
- #if 0
- run_command("ds_cpu_alarm 1500000000", 0);
- #else
- system_reset();
- #endif
- } else {
- #if 0
- run_command("ds_cpu_alarm 1500000000", 0);
- #else
- system_reset();
- #endif
- }
- //Fixmed: before irq clear !!!
- ds_hw_macro_rearm(id, irq_macro[i], size);
- ds_sensor_irq_clear(id, irq_macro[i]);
- i++;
- }
- }
- }
- if (status & DS_3_ERR) {
- printf("apb digital sensor3 detect error event\n");
- apb_ds[j++] = 4;
- }
- if (status & DS_4_ERR) {
- printf("apb digital sensor4 detect error event\n");
- apb_ds[j++] = 5;
- }
- if (status & DS_5_ERR) {
- printf("apb digital sensor5 detect error event\n");
- apb_ds[j++] = 6;
- }
- if (status & DS_6_ERR) {
- printf("apb digital sensor6 detect error event\n");
- apb_ds[j++] = 7;
- }
- if (status & DS_7_ERR) {
- printf("apb digital sensor7 detect error event\n");
- apb_ds[j++] = 8;
- }
- while (apb_ds[t]) {
- if (apb_ds[t] < 4 || apb_ds[t] > 8) {
- printf("invalid digial sensor id(%d)\n", apb_ds[t]);
- return;
- }
- for (i = 0; i < ARRAY_SIZE(irq_macro); i++)
- irq_macro[i] = DS_INVALID_MACRO_ID;
- size = ds_array[apb_ds[t]].hw_macro_num;
- if (ds_sensor_irq_hw_macro_get(apb_ds[t], irq_macro)) {
- i = 0;
- while (i < MAX_HW_MACRO_NUM_PER_DS && irq_macro[i] != DS_INVALID_MACRO_ID) {//hardware macro
- debug("[%s,%d]irq_status = 0x%x, alarm_status = 0x%x\n", __func__, __LINE__,
- readl(REG_IRQ_STATUS(apb_ds[t])), readl(REG_SENSOR_ALARM(apb_ds[t])));
- tl = ds_hw_macro_threat_level_get(apb_ds[t], irq_macro[i]);
- if (tl)
- printf("DS%d-MACRO%d Threat Level: 0x%x\n", apb_ds[t], irq_macro[i], tl);
- if (apb_ds[t] == 8 && tl >= CFG_APB1_THREAT_LEVEL) {
- //handle1
- run_command("ds_3to6_alarm 4", 0);
- } else if (tl >= CFG_APB0_THREAT_LEVEL) {
- //handle2
- run_command("ds_3to6_alarm 4", 0);
- } else {
- //handle3
- run_command("ds_3to6_alarm 4", 0);
- }
- //Fixmed: before irq clear !!!
- ds_hw_macro_rearm(apb_ds[t], irq_macro[i], size);
- ds_sensor_irq_clear(apb_ds[t], irq_macro[i]);
- i++;
- }
- }
- t++; //digital number
- }
- }
- static int ds_platform_init(void)
- {
- int ds_id, macro_id, ret = 0;
- for (ds_id = 0; ds_id < MAX_DIGITAL_SENSOR_NUM; ds_id++) {
- printf("Digital Sensor%d HW Version: 0x%x\n", ds_id, readl(REG_HW_VERSION(ds_id)));
- for (macro_id = 0; macro_id < ds_array[ds_id].hw_macro_num; macro_id++) {
- ds_hw_macro_sensor_alarm_endisable(ds_id,
- macro_id, true);
- ds_hw_macro_health_test_start(ds_id, macro_id);
- udelay(5);
- ret = ds_health_test_done_status(ds_id, macro_id);
- if (!ret) {
- printf("health test failed for DS%d-Macro%d\n", ds_id, macro_id);
- ds_hw_macro_sensor_alarm_endisable(ds_id,
- macro_id, false);
- } else {
- ret = ds_health_test_alarm_status(ds_id, macro_id);
- if (ret) {
- ds_hw_macro_sensor_alarm_endisable(ds_id,
- macro_id, false);
- printf("health test failed for DS%d-Macro%d\n", ds_id, macro_id);
- }
- }
- }
- }
- return 0;
- }
- static int ds_sec_interrupt_init(void)
- {
- int ret;
- ret = irq_handler_register(LIGHT_SEC_IRQ_NUM, light_sec_irq_handler);
- if (ret) {
- printf("failed to register security interrupt handler\n");
- return ret;
- }
- irq_priority_set(LIGHT_SEC_IRQ_NUM);
- irq_enable(LIGHT_SEC_IRQ_NUM);
- return 0;
- }
- void ds_uninit(void)
- {
- int ds_id, macro_id;
- irq_disable(LIGHT_SEC_IRQ_NUM);
- for (ds_id = 0; ds_id < MAX_DIGITAL_SENSOR_NUM; ds_id++) {
- for (macro_id = 0; macro_id < ds_array[ds_id].hw_macro_num; macro_id++)
- ds_hw_macro_sensor_alarm_endisable(ds_id, macro_id, false);
- }
- irq_handler_register(LIGHT_SEC_IRQ_NUM, NULL);
- }
- int ds_init(void)
- {
- int ret;
- ds_platform_init();
- ret = ds_sec_interrupt_init();
- if (ret)
- return ret;
- return 0;
- }
|