imx8: Configure SNVS
authorFranck LENORMAND <franck.lenormand@nxp.com>
Wed, 9 Oct 2019 08:27:43 +0000 (10:27 +0200)
committerStefano Babic <sbabic@denx.de>
Fri, 1 May 2020 11:46:22 +0000 (13:46 +0200)
Add a module to configure the tamper and secure violation of
the SNVS using the SCU API.

The module also adds some commands:
 - snvs_cfg: Configure the SNVS HP and LP registers
 - snvs_dgo_cfg: Configure the SNVS DGO bloc if present (8QXP)
 - tamper_pin_cfg: Change the configuration of the tamper pins
 - snvs_clear_status: Allow to write to LPSR and LPTDSR to clear
   status bits

Reviewed-by: Fabio Estevam <festevam@gmail.com>
Signed-off-by: Franck LENORMAND <franck.lenormand@nxp.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
arch/arm/include/asm/arch-imx8/sci/sci.h
arch/arm/include/asm/arch-imx8/snvs_security_sc.h [new file with mode: 0644]
arch/arm/mach-imx/imx8/Kconfig
arch/arm/mach-imx/imx8/Makefile
arch/arm/mach-imx/imx8/snvs_security_sc.c [new file with mode: 0644]
board/freescale/imx8qxp_mek/imx8qxp_mek.c
drivers/misc/imx8/scu_api.c

index 179037ae17e4709bbb2c0b5ee48eb6d8734e077b..05f736f14f0f1babae863482302736fc609cb5d2 100644 (file)
@@ -109,6 +109,7 @@ int sc_rm_get_resource_owner(sc_ipc_t ipc, sc_rsrc_t resource,
 
 /* PAD API */
 int sc_pad_set(sc_ipc_t ipc, sc_pad_t pad, u32 val);
+int sc_pad_get(sc_ipc_t ipc, sc_pad_t pad, uint32_t *val);
 
 /* SMMU API */
 int sc_rm_set_master_sid(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t sid);
@@ -128,5 +129,8 @@ int sc_seco_update_mpmr(sc_ipc_t ipc, sc_faddr_t addr, u8 size, u8 lock);
 int sc_seco_get_mp_sign(sc_ipc_t ipc, sc_faddr_t msg_addr,
                        u16 msg_size, sc_faddr_t dst_addr, u16 dst_size);
 int sc_seco_secvio_dgo_config(sc_ipc_t ipc, u8 id, u8 access, u32 *data);
+int sc_seco_secvio_config(sc_ipc_t ipc, u8 id, u8 access,
+                         u32 *data0, u32 *data1, u32 *data2, u32 *data3,
+                         u32 *data4, u8 size);
 
 #endif
diff --git a/arch/arm/include/asm/arch-imx8/snvs_security_sc.h b/arch/arm/include/asm/arch-imx8/snvs_security_sc.h
new file mode 100644 (file)
index 0000000..0b7ded7
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ */
+
+#ifndef _SNVS_SECURITY_SC_H
+#define _SNVS_SECURITY_SC_H
+
+int snvs_security_sc_init(void);
+
+#endif /* _SNVS_SECURITY_SC_H */
index 5827ab334f6f446af8edfb66f25f9defa773017e..1f8add015f4eb752470173430327207240130433 100644 (file)
@@ -90,4 +90,17 @@ source "board/toradex/apalis-imx8/Kconfig"
 source "board/toradex/colibri-imx8x/Kconfig"
 source "board/siemens/capricorn/Kconfig"
 
+config IMX_SNVS_SEC_SC
+       bool "Support SNVS configuration"
+       help
+         Allow to configure the SNVS via SCU API to configure tampers and secure
+         violation.
+
+config IMX_SNVS_SEC_SC_AUTO
+       bool "Support SNVS configuration command"
+       depends on IMX_SNVS_SEC_SC
+       help
+         This configuration will apply the selected configurations automatically
+         at boot.
+
 endif
index 7ffb7e95b2512ef8278a10beeee3a4b4e03dd990..bbb41adbe43c54503c956eb992d87ae12a5d130a 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_AHAB_BOOT) += ahab.o
 ifdef CONFIG_SPL_BUILD
 obj-$(CONFIG_SPL_LOAD_IMX_CONTAINER) += image.o parse-container.o
 endif
+obj-$(CONFIG_IMX_SNVS_SEC_SC) += snvs_security_sc.o
diff --git a/arch/arm/mach-imx/imx8/snvs_security_sc.c b/arch/arm/mach-imx/imx8/snvs_security_sc.c
new file mode 100644 (file)
index 0000000..73f5651
--- /dev/null
@@ -0,0 +1,923 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2019-2020 NXP.
+ */
+
+/*
+ * Configuration of the Tamper pins in different mode:
+ *  - default (no tamper pins): _default_
+ *  - passive mode expecting VCC on the line: "_passive_vcc_"
+ *  - passive mode expecting VCC on the line: "_passive_gnd_"
+ *  - active mode: "_active_"
+ */
+
+#include <command.h>
+#include <log.h>
+#include <stddef.h>
+#include <common.h>
+#include <asm/arch/sci/sci.h>
+#include <asm/arch-imx8/imx8-pins.h>
+#include <asm/arch-imx8/snvs_security_sc.h>
+
+/* Access to gd */
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SC_WRITE_CONF 1
+
+#define PGD_HEX_VALUE 0x41736166
+#define SRTC_EN 0x1
+#define DP_EN BIT(5)
+
+struct snvs_security_sc_conf {
+       struct snvs_hp_conf {
+               u32 lock;               /* HPLR - HP Lock */
+               u32 __cmd;              /* HPCOMR - HP Command */
+               u32 __ctl;              /* HPCR - HP Control */
+               u32 secvio_intcfg;      /* HPSICR - Security Violation Int
+                                        * Config
+                                        */
+               u32 secvio_ctl;         /* HPSVCR - Security Violation Control*/
+               u32 status;             /* HPSR - HP Status */
+               u32 secvio_status;      /* HPSVSR - Security Violation Status */
+               u32 __ha_counteriv;     /* High Assurance Counter IV */
+               u32 __ha_counter;               /* High Assurance Counter */
+               u32 __rtc_msb;          /* Real Time Clock/Counter MSB */
+               u32 __rtc_lsb;          /* Real Time Counter LSB */
+               u32 __time_alarm_msb;   /* Time Alarm MSB */
+               u32 __time_alarm_lsb;   /* Time Alarm LSB */
+       } hp;
+       struct snvs_lp_conf {
+               u32 lock;
+               u32 __ctl;
+               u32 __mstr_key_ctl;     /* Master Key Control */
+               u32 secvio_ctl;         /* Security Violation Control */
+               u32 tamper_filt_cfg;    /* Tamper Glitch Filters Configuration*/
+               u32 tamper_det_cfg;     /* Tamper Detectors Configuration */
+               u32 status;
+               u32 __srtc_msb;         /* Secure Real Time Clock/Counter MSB */
+               u32 __srtc_lsb;         /* Secure Real Time Clock/Counter LSB */
+               u32 __time_alarm;               /* Time Alarm */
+               u32 __smc_msb;          /* Secure Monotonic Counter MSB */
+               u32 __smc_lsb;          /* Secure Monotonic Counter LSB */
+               u32 __pwr_glitch_det;   /* Power Glitch Detector */
+               u32 __gen_purpose;
+               u8 __zmk[32];           /* Zeroizable Master Key */
+               u32 __rsvd0;
+               u32 __gen_purposes[4];  /* gp0_30 to gp0_33 */
+               u32 tamper_det_cfg2;    /* Tamper Detectors Configuration2 */
+               u32 tamper_det_status;  /* Tamper Detectors status */
+               u32 tamper_filt1_cfg;   /* Tamper Glitch Filter1 Configuration*/
+               u32 tamper_filt2_cfg;   /* Tamper Glitch Filter2 Configuration*/
+               u32 __rsvd1[4];
+               u32 act_tamper1_cfg;    /* Active Tamper1 Configuration */
+               u32 act_tamper2_cfg;    /* Active Tamper2 Configuration */
+               u32 act_tamper3_cfg;    /* Active Tamper3 Configuration */
+               u32 act_tamper4_cfg;    /* Active Tamper4 Configuration */
+               u32 act_tamper5_cfg;    /* Active Tamper5 Configuration */
+               u32 __rsvd2[3];
+               u32 act_tamper_ctl;     /* Active Tamper Control */
+               u32 act_tamper_clk_ctl; /* Active Tamper Clock Control */
+               u32 act_tamper_routing_ctl1;/* Active Tamper Routing Control1 */
+               u32 act_tamper_routing_ctl2;/* Active Tamper Routing Control2 */
+       } lp;
+};
+
+static struct snvs_security_sc_conf snvs_default_config = {
+       .hp = {
+               .lock = 0x1f0703ff,
+               .secvio_ctl = 0x3000007f,
+       },
+       .lp = {
+               .lock = 0x1f0003ff,
+               .secvio_ctl = 0x36,
+               .tamper_filt_cfg = 0,
+               .tamper_det_cfg = 0x76, /* analogic tampers
+                                        * + rollover tampers
+                                        */
+               .tamper_det_cfg2 = 0,
+               .tamper_filt1_cfg = 0,
+               .tamper_filt2_cfg = 0,
+               .act_tamper1_cfg = 0,
+               .act_tamper2_cfg = 0,
+               .act_tamper3_cfg = 0,
+               .act_tamper4_cfg = 0,
+               .act_tamper5_cfg = 0,
+               .act_tamper_ctl = 0,
+               .act_tamper_clk_ctl = 0,
+               .act_tamper_routing_ctl1 = 0,
+               .act_tamper_routing_ctl2 = 0,
+       }
+};
+
+static struct snvs_security_sc_conf snvs_passive_vcc_config = {
+       .hp = {
+               .lock = 0x1f0703ff,
+               .secvio_ctl = 0x3000007f,
+       },
+       .lp = {
+               .lock = 0x1f0003ff,
+               .secvio_ctl = 0x36,
+               .tamper_filt_cfg = 0,
+               .tamper_det_cfg = 0x276, /* ET1 will trig on line at GND
+                                         *  + analogic tampers
+                                         *  + rollover tampers
+                                         */
+               .tamper_det_cfg2 = 0,
+               .tamper_filt1_cfg = 0,
+               .tamper_filt2_cfg = 0,
+               .act_tamper1_cfg = 0,
+               .act_tamper2_cfg = 0,
+               .act_tamper3_cfg = 0,
+               .act_tamper4_cfg = 0,
+               .act_tamper5_cfg = 0,
+               .act_tamper_ctl = 0,
+               .act_tamper_clk_ctl = 0,
+               .act_tamper_routing_ctl1 = 0,
+               .act_tamper_routing_ctl2 = 0,
+       }
+};
+
+static struct snvs_security_sc_conf snvs_passive_gnd_config = {
+       .hp = {
+               .lock = 0x1f0703ff,
+               .secvio_ctl = 0x3000007f,
+       },
+       .lp = {
+               .lock = 0x1f0003ff,
+               .secvio_ctl = 0x36,
+               .tamper_filt_cfg = 0,
+               .tamper_det_cfg = 0xa76, /* ET1 will trig on line at VCC
+                                         *  + analogic tampers
+                                         *  + rollover tampers
+                                         */
+               .tamper_det_cfg2 = 0,
+               .tamper_filt1_cfg = 0,
+               .tamper_filt2_cfg = 0,
+               .act_tamper1_cfg = 0,
+               .act_tamper2_cfg = 0,
+               .act_tamper3_cfg = 0,
+               .act_tamper4_cfg = 0,
+               .act_tamper5_cfg = 0,
+               .act_tamper_ctl = 0,
+               .act_tamper_clk_ctl = 0,
+               .act_tamper_routing_ctl1 = 0,
+               .act_tamper_routing_ctl2 = 0,
+       }
+};
+
+static struct snvs_security_sc_conf snvs_active_config = {
+       .hp = {
+               .lock = 0x1f0703ff,
+               .secvio_ctl = 0x3000007f,
+       },
+       .lp = {
+               .lock = 0x1f0003ff,
+               .secvio_ctl = 0x36,
+               .tamper_filt_cfg = 0x00800000, /* Enable filtering */
+               .tamper_det_cfg = 0x276, /* ET1 enabled + analogic tampers
+                                         *  + rollover tampers
+                                         */
+               .tamper_det_cfg2 = 0,
+               .tamper_filt1_cfg = 0,
+               .tamper_filt2_cfg = 0,
+               .act_tamper1_cfg = 0x84001111,
+               .act_tamper2_cfg = 0,
+               .act_tamper3_cfg = 0,
+               .act_tamper4_cfg = 0,
+               .act_tamper5_cfg = 0,
+               .act_tamper_ctl = 0x00010001,
+               .act_tamper_clk_ctl = 0,
+               .act_tamper_routing_ctl1 = 0x1,
+               .act_tamper_routing_ctl2 = 0,
+       }
+};
+
+static struct snvs_security_sc_conf *get_snvs_config(void)
+{
+       return &snvs_default_config;
+}
+
+struct snvs_dgo_conf {
+       u32 tamper_offset_ctl;
+       u32 tamper_pull_ctl;
+       u32 tamper_ana_test_ctl;
+       u32 tamper_sensor_trim_ctl;
+       u32 tamper_misc_ctl;
+       u32 tamper_core_volt_mon_ctl;
+};
+
+static struct snvs_dgo_conf snvs_dgo_default_config = {
+       .tamper_misc_ctl = 0x80000000, /* Lock the DGO */
+};
+
+static struct snvs_dgo_conf snvs_dgo_passive_vcc_config = {
+       .tamper_misc_ctl = 0x80000000, /* Lock the DGO */
+       .tamper_pull_ctl = 0x00000001, /* Pull down ET1 */
+       .tamper_ana_test_ctl = 0x20000000, /* Enable tamper */
+};
+
+static struct snvs_dgo_conf snvs_dgo_passive_gnd_config = {
+       .tamper_misc_ctl = 0x80000000, /* Lock the DGO */
+       .tamper_pull_ctl = 0x00000401, /* Pull up ET1 */
+       .tamper_ana_test_ctl = 0x20000000, /* Enable tamper */
+};
+
+static struct snvs_dgo_conf snvs_dgo_active_config = {
+       .tamper_misc_ctl = 0x80000000, /* Lock the DGO */
+       .tamper_ana_test_ctl = 0x20000000, /* Enable tamper */
+};
+
+static struct snvs_dgo_conf *get_snvs_dgo_config(void)
+{
+       return &snvs_dgo_default_config;
+}
+
+struct tamper_pin_cfg {
+       u32 pad;
+       u32 mux_conf;
+};
+
+static struct tamper_pin_cfg tamper_pin_list_default_config[] = {
+       {SC_P_CSI_D00, 0}, /* Tamp_Out0 */
+       {SC_P_CSI_D01, 0}, /* Tamp_Out1 */
+       {SC_P_CSI_D02, 0}, /* Tamp_Out2 */
+       {SC_P_CSI_D03, 0}, /* Tamp_Out3 */
+       {SC_P_CSI_D04, 0}, /* Tamp_Out4 */
+       {SC_P_CSI_D05, 0}, /* Tamp_In0 */
+       {SC_P_CSI_D06, 0}, /* Tamp_In1 */
+       {SC_P_CSI_D07, 0}, /* Tamp_In2 */
+       {SC_P_CSI_HSYNC, 0}, /* Tamp_In3 */
+       {SC_P_CSI_VSYNC, 0}, /* Tamp_In4 */
+};
+
+static struct tamper_pin_cfg tamper_pin_list_passive_vcc_config[] = {
+       {SC_P_CSI_D05, 0x1c000060}, /* Tamp_In0 */ /* Sel tamper + OD input */
+};
+
+static struct tamper_pin_cfg tamper_pin_list_passive_gnd_config[] = {
+       {SC_P_CSI_D05, 0x1c000060}, /* Tamp_In0 */ /* Sel tamper + OD input */
+};
+
+static struct tamper_pin_cfg tamper_pin_list_active_config[] = {
+       {SC_P_CSI_D00, 0x1a000060}, /* Tamp_Out0 */ /* Sel tamper + OD */
+       {SC_P_CSI_D05, 0x1c000060}, /* Tamp_In0 */ /* Sel tamper + OD input */
+};
+
+#define TAMPER_PIN_LIST_CHOSEN tamper_pin_list_default_config
+
+static struct tamper_pin_cfg *get_tamper_pin_cfg_list(u32 *size)
+{
+       *size = sizeof(TAMPER_PIN_LIST_CHOSEN) /
+               sizeof(TAMPER_PIN_LIST_CHOSEN[0]);
+
+       return TAMPER_PIN_LIST_CHOSEN;
+}
+
+#define SC_CONF_OFFSET_OF(_field) \
+       (offsetof(struct snvs_security_sc_conf, _field))
+
+static u32 ptr_value(u32 *_p)
+{
+       return (_p) ? *_p : 0xdeadbeef;
+}
+
+static int check_write_secvio_config(u32 id, u32 *_p1, u32 *_p2,
+                                    u32 *_p3, u32 *_p4, u32 *_p5,
+                                    u32 _cnt)
+{
+       int scierr = 0;
+       u32 d1 = ptr_value(_p1);
+       u32 d2 = ptr_value(_p2);
+       u32 d3 = ptr_value(_p3);
+       u32 d4 = ptr_value(_p4);
+       u32 d5 = ptr_value(_p5);
+
+       scierr = sc_seco_secvio_config(-1, id, SC_WRITE_CONF, &d1, &d2, &d3,
+                                      &d4, &d4, _cnt);
+       if (scierr != SC_ERR_NONE) {
+               printf("Failed to set secvio configuration\n");
+               debug("Failed to set conf id 0x%x with values ", id);
+               debug("0x%.8x 0x%.8x 0x%.8x 0x%.8x 0x%.8x (cnt: %d)\n",
+                     d1, d2, d3, d4, d5, _cnt);
+               goto exit;
+       }
+
+       if (_p1)
+               *(u32 *)_p1 = d1;
+       if (_p2)
+               *(u32 *)_p2 = d2;
+       if (_p3)
+               *(u32 *)_p3 = d3;
+       if (_p4)
+               *(u32 *)_p4 = d4;
+       if (_p5)
+               *(u32 *)_p5 = d5;
+
+exit:
+       return scierr;
+}
+
+#define SC_CHECK_WRITE1(id, _p1) \
+       check_write_secvio_config(id, _p1, NULL, NULL, NULL, NULL, 1)
+
+static int apply_snvs_config(struct snvs_security_sc_conf *cnf)
+{
+       int scierr = 0;
+
+       debug("%s\n", __func__);
+
+       debug("Applying config:\n"
+                 "\thp.lock = 0x%.8x\n"
+                 "\thp.secvio_ctl = 0x%.8x\n"
+                 "\tlp.lock = 0x%.8x\n"
+                 "\tlp.secvio_ctl = 0x%.8x\n"
+                 "\tlp.tamper_filt_cfg = 0x%.8x\n"
+                 "\tlp.tamper_det_cfg = 0x%.8x\n"
+                 "\tlp.tamper_det_cfg2 = 0x%.8x\n"
+                 "\tlp.tamper_filt1_cfg = 0x%.8x\n"
+                 "\tlp.tamper_filt2_cfg = 0x%.8x\n"
+                 "\tlp.act_tamper1_cfg = 0x%.8x\n"
+                 "\tlp.act_tamper2_cfg = 0x%.8x\n"
+                 "\tlp.act_tamper3_cfg = 0x%.8x\n"
+                 "\tlp.act_tamper4_cfg = 0x%.8x\n"
+                 "\tlp.act_tamper5_cfg = 0x%.8x\n"
+                 "\tlp.act_tamper_ctl = 0x%.8x\n"
+                 "\tlp.act_tamper_clk_ctl = 0x%.8x\n"
+                 "\tlp.act_tamper_routing_ctl1 = 0x%.8x\n"
+                 "\tlp.act_tamper_routing_ctl2 = 0x%.8x\n",
+                       cnf->hp.lock,
+                       cnf->hp.secvio_ctl,
+                       cnf->lp.lock,
+                       cnf->lp.secvio_ctl,
+                       cnf->lp.tamper_filt_cfg,
+                       cnf->lp.tamper_det_cfg,
+                       cnf->lp.tamper_det_cfg2,
+                       cnf->lp.tamper_filt1_cfg,
+                       cnf->lp.tamper_filt2_cfg,
+                       cnf->lp.act_tamper1_cfg,
+                       cnf->lp.act_tamper2_cfg,
+                       cnf->lp.act_tamper3_cfg,
+                       cnf->lp.act_tamper4_cfg,
+                       cnf->lp.act_tamper5_cfg,
+                       cnf->lp.act_tamper_ctl,
+                       cnf->lp.act_tamper_clk_ctl,
+                       cnf->lp.act_tamper_routing_ctl1,
+                       cnf->lp.act_tamper_routing_ctl2);
+
+       scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_filt_cfg),
+                                          &cnf->lp.tamper_filt_cfg,
+                                          &cnf->lp.tamper_filt1_cfg,
+                                          &cnf->lp.tamper_filt2_cfg, NULL,
+                                          NULL, 3);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Configure AT */
+       scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper1_cfg),
+                                          &cnf->lp.act_tamper1_cfg,
+                                          &cnf->lp.act_tamper2_cfg,
+                                          &cnf->lp.act_tamper2_cfg,
+                                          &cnf->lp.act_tamper2_cfg,
+                                          &cnf->lp.act_tamper2_cfg, 5);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Configure AT routing */
+       scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.act_tamper_routing_ctl1),
+                                          &cnf->lp.act_tamper_routing_ctl1,
+                                          &cnf->lp.act_tamper_routing_ctl2,
+                                          NULL, NULL, NULL, 2);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Configure AT frequency */
+       scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_clk_ctl),
+                                &cnf->lp.act_tamper_clk_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Activate the ATs */
+       scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.act_tamper_ctl),
+                                &cnf->lp.act_tamper_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Activate the detectors */
+       scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_cfg),
+                                          &cnf->lp.tamper_det_cfg,
+                                          &cnf->lp.tamper_det_cfg2, NULL, NULL,
+                                          NULL, 2);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Configure LP secvio */
+       scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.secvio_ctl),
+                                &cnf->lp.secvio_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Configure HP secvio */
+       scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.secvio_ctl),
+                                &cnf->hp.secvio_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Lock access */
+       scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(hp.lock), &cnf->hp.lock);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       scierr = SC_CHECK_WRITE1(SC_CONF_OFFSET_OF(lp.lock), &cnf->lp.lock);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+exit:
+       return (scierr == SC_ERR_NONE) ? 0 : -EIO;
+}
+
+static int dgo_write(u32 _id, u8 _access, u32 *_pdata)
+{
+       int scierr = sc_seco_secvio_dgo_config(-1, _id, _access, _pdata);
+
+       if (scierr != SC_ERR_NONE) {
+               printf("Failed to set dgo configuration\n");
+               debug("Failed to set conf id 0x%x : 0x%.8x", _id, *_pdata);
+       }
+
+       return scierr;
+}
+
+static int apply_snvs_dgo_config(struct snvs_dgo_conf *cnf)
+{
+       int scierr = 0;
+
+       debug("%s\n", __func__);
+
+       debug("Applying config:\n"
+               "\ttamper_offset_ctl = 0x%.8x\n"
+               "\ttamper_pull_ctl = 0x%.8x\n"
+               "\ttamper_ana_test_ctl = 0x%.8x\n"
+               "\ttamper_sensor_trim_ctl = 0x%.8x\n"
+               "\ttamper_misc_ctl = 0x%.8x\n"
+               "\ttamper_core_volt_mon_ctl = 0x%.8x\n",
+                       cnf->tamper_offset_ctl,
+                       cnf->tamper_pull_ctl,
+                       cnf->tamper_ana_test_ctl,
+                       cnf->tamper_sensor_trim_ctl,
+                       cnf->tamper_misc_ctl,
+                       cnf->tamper_core_volt_mon_ctl);
+
+       dgo_write(0x04, 1, &cnf->tamper_offset_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       dgo_write(0x14, 1, &cnf->tamper_pull_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       dgo_write(0x24, 1, &cnf->tamper_ana_test_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       dgo_write(0x34, 1, &cnf->tamper_sensor_trim_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       dgo_write(0x54, 1, &cnf->tamper_core_volt_mon_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       /* Last as it could lock the writes */
+       dgo_write(0x44, 1, &cnf->tamper_misc_ctl);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+exit:
+       return (scierr == SC_ERR_NONE) ? 0 : -EIO;
+}
+
+static int pad_write(u32 _pad, u32 _value)
+{
+       int scierr = sc_pad_set(-1, _pad, _value);
+
+       if (scierr != SC_ERR_NONE) {
+               printf("Failed to set pad configuration\n");
+               debug("Failed to set conf pad 0x%x : 0x%.8x", _pad, _value);
+       }
+
+       return scierr;
+}
+
+static int apply_tamper_pin_list_config(struct tamper_pin_cfg *confs, u32 size)
+{
+       int scierr = 0;
+       u32 idx;
+
+       debug("%s\n", __func__);
+
+       for (idx = 0; idx < size; idx++) {
+               debug("\t idx %d: pad %d: 0x%.8x\n", idx, confs[idx].pad,
+                     confs[idx].mux_conf);
+               pad_write(confs[idx].pad, 3 << 30 | confs[idx].mux_conf);
+               if (scierr != SC_ERR_NONE)
+                       goto exit;
+       }
+
+exit:
+       return (scierr == SC_ERR_NONE) ? 0 : -EIO;
+}
+
+int examples(void)
+{
+       u32 size;
+       struct snvs_security_sc_conf *snvs_conf;
+       struct snvs_dgo_conf *snvs_dgo_conf;
+       struct tamper_pin_cfg *tamper_pin_conf;
+
+       /* Caller */
+       snvs_conf = get_snvs_config();
+       snvs_dgo_conf = get_snvs_dgo_config();
+       tamper_pin_conf = get_tamper_pin_cfg_list(&size);
+
+       /* Default */
+       snvs_conf = &snvs_default_config;
+       snvs_dgo_conf = &snvs_dgo_default_config;
+       tamper_pin_conf = tamper_pin_list_default_config;
+
+       /* Passive tamper expecting VCC on the line */
+       snvs_conf = &snvs_passive_vcc_config;
+       snvs_dgo_conf = &snvs_dgo_passive_vcc_config;
+       tamper_pin_conf = tamper_pin_list_passive_vcc_config;
+
+       /* Passive tamper expecting GND on the line */
+       snvs_conf = &snvs_passive_gnd_config;
+       snvs_dgo_conf = &snvs_dgo_passive_gnd_config;
+       tamper_pin_conf = tamper_pin_list_passive_gnd_config;
+
+       /* Active tamper */
+       snvs_conf = &snvs_active_config;
+       snvs_dgo_conf = &snvs_dgo_active_config;
+       tamper_pin_conf = tamper_pin_list_active_config;
+
+       return !snvs_conf + !snvs_dgo_conf + !tamper_pin_conf;
+}
+
+#ifdef CONFIG_IMX_SNVS_SEC_SC_AUTO
+int snvs_security_sc_init(void)
+{
+       int err = 0;
+
+       struct snvs_security_sc_conf *snvs_conf;
+       struct snvs_dgo_conf *snvs_dgo_conf;
+       struct tamper_pin_cfg *tamper_pin_conf;
+       u32 size;
+
+       debug("%s\n", __func__);
+
+       snvs_conf = get_snvs_config();
+       snvs_dgo_conf = get_snvs_dgo_config();
+
+       tamper_pin_conf = get_tamper_pin_cfg_list(&size);
+
+       err = apply_tamper_pin_list_config(tamper_pin_conf, size);
+       if (err) {
+               debug("Failed to set pins\n");
+               goto exit;
+       }
+
+       err = apply_snvs_dgo_config(snvs_dgo_conf);
+       if (err) {
+               debug("Failed to set dgo\n");
+               goto exit;
+       }
+
+       err = apply_snvs_config(snvs_conf);
+       if (err) {
+               debug("Failed to set snvs\n");
+               goto exit;
+       }
+
+exit:
+       return err;
+}
+#endif /* CONFIG_IMX_SNVS_SEC_SC_AUTO */
+
+static char snvs_cfg_help_text[] =
+       "snvs_cfg\n"
+       "\thp.lock\n"
+       "\thp.secvio_ctl\n"
+       "\tlp.lock\n"
+       "\tlp.secvio_ctl\n"
+       "\tlp.tamper_filt_cfg\n"
+       "\tlp.tamper_det_cfg\n"
+       "\tlp.tamper_det_cfg2\n"
+       "\tlp.tamper_filt1_cfg\n"
+       "\tlp.tamper_filt2_cfg\n"
+       "\tlp.act_tamper1_cfg\n"
+       "\tlp.act_tamper2_cfg\n"
+       "\tlp.act_tamper3_cfg\n"
+       "\tlp.act_tamper4_cfg\n"
+       "\tlp.act_tamper5_cfg\n"
+       "\tlp.act_tamper_ctl\n"
+       "\tlp.act_tamper_clk_ctl\n"
+       "\tlp.act_tamper_routing_ctl1\n"
+       "\tlp.act_tamper_routing_ctl2\n"
+       "\n"
+       "ALL values should be in hexadecimal format";
+
+#define NB_REGISTERS 18
+static int do_snvs_cfg(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+       int err = 0;
+       u32 idx = 0;
+
+       struct snvs_security_sc_conf conf = {0};
+
+       if (argc != (NB_REGISTERS + 1))
+               return CMD_RET_USAGE;
+
+       conf.hp.lock = simple_strtoul(argv[++idx], NULL, 16);
+       conf.hp.secvio_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.lock = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.secvio_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.tamper_filt_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.tamper_det_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.tamper_det_cfg2 = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.tamper_filt1_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.tamper_filt2_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper1_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper2_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper3_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper4_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper5_cfg = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper_clk_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper_routing_ctl1 = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.act_tamper_routing_ctl2 = simple_strtoul(argv[++idx], NULL, 16);
+
+       err = apply_snvs_config(&conf);
+
+       return err;
+}
+
+U_BOOT_CMD(snvs_cfg,
+          NB_REGISTERS + 1, 1, do_snvs_cfg,
+          "Security violation configuration",
+          snvs_cfg_help_text
+);
+
+static char snvs_dgo_cfg_help_text[] =
+       "snvs_dgo_cfg\n"
+       "\ttamper_offset_ctl\n"
+       "\ttamper_pull_ctl\n"
+       "\ttamper_ana_test_ctl\n"
+       "\ttamper_sensor_trim_ctl\n"
+       "\ttamper_misc_ctl\n"
+       "\ttamper_core_volt_mon_ctl\n"
+       "\n"
+       "ALL values should be in hexadecimal format";
+
+static int do_snvs_dgo_cfg(cmd_tbl_t *cmdtp, int flag, int argc,
+                          char *const argv[])
+{
+       int err = 0;
+       u32 idx = 0;
+
+       struct snvs_dgo_conf conf = {0};
+
+       if (argc != (6 + 1))
+               return CMD_RET_USAGE;
+
+       conf.tamper_offset_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.tamper_pull_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.tamper_ana_test_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.tamper_sensor_trim_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.tamper_misc_ctl = simple_strtoul(argv[++idx], NULL, 16);
+       conf.tamper_core_volt_mon_ctl = simple_strtoul(argv[++idx], NULL, 16);
+
+       err = apply_snvs_dgo_config(&conf);
+
+       return err;
+}
+
+U_BOOT_CMD(snvs_dgo_cfg,
+          7, 1, do_snvs_dgo_cfg,
+          "SNVS DGO configuration",
+          snvs_dgo_cfg_help_text
+);
+
+static char tamper_pin_cfg_help_text[] =
+       "snvs_dgo_cfg\n"
+       "\tpad\n"
+       "\tvalue\n"
+       "\n"
+       "ALL values should be in hexadecimal format";
+
+static int do_tamper_pin_cfg(cmd_tbl_t *cmdtp, int flag, int argc,
+                            char *const argv[])
+{
+       int err = 0;
+       u32 idx = 0;
+
+       struct tamper_pin_cfg conf = {0};
+
+       if (argc != (2 + 1))
+               return CMD_RET_USAGE;
+
+       conf.pad = simple_strtoul(argv[++idx], NULL, 10);
+       conf.mux_conf = simple_strtoul(argv[++idx], NULL, 16);
+
+       err = apply_tamper_pin_list_config(&conf, 1);
+
+       return err;
+}
+
+U_BOOT_CMD(tamper_pin_cfg,
+          3, 1, do_tamper_pin_cfg,
+          "tamper pin configuration",
+          tamper_pin_cfg_help_text
+);
+
+static char snvs_clear_status_help_text[] =
+       "snvs_clear_status\n"
+       "\tHPSR\n"
+       "\tHPSVSR\n"
+       "\tLPSR\n"
+       "\tLPTDSR\n"
+       "\n"
+       "Write the status registers with the value provided,"
+       " clearing the status";
+
+static int do_snvs_clear_status(cmd_tbl_t *cmdtp, int flag, int argc,
+                                 char *const argv[])
+{
+       int scierr = 0;
+       u32 idx = 0;
+
+       struct snvs_security_sc_conf conf = {0};
+
+       if (argc != (2 + 1))
+               return CMD_RET_USAGE;
+
+       conf.lp.status = simple_strtoul(argv[++idx], NULL, 16);
+       conf.lp.tamper_det_status = simple_strtoul(argv[++idx], NULL, 16);
+
+       scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.status),
+                                          &conf.lp.status, NULL, NULL, NULL,
+                                          NULL, 1);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+       scierr = check_write_secvio_config(SC_CONF_OFFSET_OF(lp.tamper_det_status),
+                                          &conf.lp.tamper_det_status, NULL,
+                                          NULL, NULL, NULL, 1);
+       if (scierr != SC_ERR_NONE)
+               goto exit;
+
+exit:
+       return (scierr == SC_ERR_NONE) ? 0 : 1;
+}
+
+U_BOOT_CMD(snvs_clear_status,
+          3, 1, do_snvs_clear_status,
+          "snvs clear status",
+          snvs_clear_status_help_text
+);
+
+static char snvs_sec_status_help_text[] =
+       "snvs_sec_status\n"
+       "Display information about the security related to tamper and secvio";
+
+static int do_snvs_sec_status(cmd_tbl_t *cmdtp, int flag, int argc,
+                             char *const argv[])
+{
+       int scierr;
+       u32 idx;
+
+       u32 data[5];
+
+       u32 pads[] = {
+               SC_P_CSI_D00,
+               SC_P_CSI_D01,
+               SC_P_CSI_D02,
+               SC_P_CSI_D03,
+               SC_P_CSI_D04,
+               SC_P_CSI_D05,
+               SC_P_CSI_D06,
+               SC_P_CSI_D07,
+               SC_P_CSI_HSYNC,
+               SC_P_CSI_VSYNC,
+       };
+
+       u32 fuses[] = {
+               14,
+               30,
+               31,
+               260,
+               261,
+               262,
+               263,
+               768,
+       };
+
+       struct snvs_reg {
+               u32 id;
+               u32 nb;
+       } snvs[] = {
+               /* Locks */
+               {0x0,  1},
+               {0x34, 1},
+               /* Security violation */
+               {0xc,  1},
+               {0x10, 1},
+               {0x18, 1},
+               {0x40, 1},
+               /* Temper detectors */
+               {0x48, 2},
+               {0x4c, 1},
+               {0xa4, 1},
+               /* */
+               {0x44, 3},
+               {0xe0, 1},
+               {0xe4, 1},
+               {0xe8, 2},
+               /* Misc */
+               {0x3c, 1},
+               {0x5c, 2},
+               {0x64, 1},
+               {0xf8, 2},
+       };
+
+       u32 dgo[] = {
+               0x0,
+               0x10,
+               0x20,
+               0x30,
+               0x40,
+               0x50,
+       };
+
+       /* Pins */
+       printf("Pins:\n");
+       for (idx = 0; idx < ARRAY_SIZE(pads); idx++) {
+               u8 pad_id = pads[idx];
+
+               scierr = sc_pad_get(-1, pad_id, &data[0]);
+               if (scierr == 0)
+                       printf("\t- Pin %d: %.8x\n", pad_id, data[0]);
+               else
+                       printf("Failed to read Pin %d\n", pad_id);
+       }
+
+       /* Fuses */
+       printf("Fuses:\n");
+       for (idx = 0; idx < ARRAY_SIZE(fuses); idx++) {
+               u32 fuse_id = fuses[idx];
+
+               scierr = sc_misc_otp_fuse_read(-1, fuse_id, &data[0]);
+               if (scierr == 0)
+                       printf("\t- Fuse %d: %.8x\n", fuse_id, data[0]);
+               else
+                       printf("Failed to read Fuse %d\n", fuse_id);
+       }
+
+       /* SNVS */
+       printf("SNVS:\n");
+       for (idx = 0; idx < ARRAY_SIZE(snvs); idx++) {
+               struct snvs_reg *reg = &snvs[idx];
+
+               scierr = sc_seco_secvio_config(-1, reg->id, 0, &data[0],
+                                              &data[1], &data[2], &data[3],
+                                              &data[4], reg->nb);
+               if (scierr == 0) {
+                       int subidx;
+
+                       printf("\t- SNVS %.2x(%d):", reg->id, reg->nb);
+                       for (subidx = 0; subidx < reg->nb; subidx++)
+                               printf(" %.8x", data[subidx]);
+                       printf("\n");
+               } else {
+                       printf("Failed to read SNVS %d\n", reg->id);
+               }
+       }
+
+       /* DGO */
+       printf("DGO:\n");
+       for (idx = 0; idx < ARRAY_SIZE(dgo); idx++) {
+               u8 dgo_id = dgo[idx];
+
+               scierr = sc_seco_secvio_dgo_config(-1, dgo_id, 0, &data[0]);
+               if (scierr == 0)
+                       printf("\t- DGO %.2x: %.8x\n", dgo_id, data[0]);
+               else
+                       printf("Failed to read DGO %d\n", dgo_id);
+       }
+
+       return 0;
+}
+
+U_BOOT_CMD(snvs_sec_status,
+          1, 1, do_snvs_sec_status,
+          "tamper pin configuration",
+          snvs_sec_status_help_text
+);
index b96f0da21efb636656a83825a463f6c123c7512c..93f0cd827c31557dc2c8c4f3b8ddedef922d453d 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/sci/sci.h>
 #include <asm/arch/imx8-pins.h>
+#include <asm/arch/snvs_security_sc.h>
 #include <asm/arch/iomux.h>
 #include <asm/arch/sys_proto.h>
 
@@ -111,6 +112,15 @@ int board_init(void)
 {
        board_gpio_init();
 
+#ifdef CONFIG_IMX_SNVS_SEC_SC_AUTO
+       {
+               int ret = snvs_security_sc_init();
+
+               if (ret)
+                       return ret;
+       }
+#endif
+
        return 0;
 }
 
index 227bc5287374122504fe465f36d7280361933b01..3e38edbf5dc3499a6db2c1928304e0af9259f94d 100644 (file)
@@ -222,6 +222,34 @@ int sc_pad_set(sc_ipc_t ipc, sc_pad_t pad, u32 val)
        return ret;
 }
 
+int sc_pad_get(sc_ipc_t ipc, sc_pad_t pad, u32 *val)
+{
+       struct udevice *dev = gd->arch.scu_dev;
+       int size = sizeof(struct sc_rpc_msg_s);
+       struct sc_rpc_msg_s msg;
+       int ret;
+
+       if (!dev)
+               hang();
+
+       RPC_VER(&msg) = SC_RPC_VERSION;
+       RPC_SIZE(&msg) = 2U;
+       RPC_SVC(&msg) = (u8)(SC_RPC_SVC_PAD);
+       RPC_FUNC(&msg) = (u8)(PAD_FUNC_GET);
+
+       RPC_U16(&msg, 0U) = (u16)(pad);
+
+       ret = misc_call(dev, SC_FALSE, &msg, size, &msg, size);
+       if (ret)
+               printf("%s: pad:%d: res:%d\n",
+                      __func__, pad, RPC_R8(&msg));
+
+       if (val)
+               *val = (u32)RPC_U32(&msg, 0U);
+
+       return ret;
+}
+
 /* MISC */
 int sc_misc_set_control(sc_ipc_t ipc, sc_rsrc_t resource,
                        sc_ctrl_t ctrl, u32 val)
@@ -996,8 +1024,8 @@ int sc_seco_get_mp_key(sc_ipc_t ipc, sc_faddr_t dst_addr,
        return ret;
 }
 
-int sc_seco_update_mpmr(sc_ipc_t ipc, sc_faddr_t addr, uint8_t size_m,
-                       uint8_t lock)
+int sc_seco_update_mpmr(sc_ipc_t ipc, sc_faddr_t addr, u8 size_m,
+                       u8 lock)
 {
        struct udevice *dev = gd->arch.scu_dev;
        struct sc_rpc_msg_s msg;
@@ -1051,8 +1079,44 @@ int sc_seco_get_mp_sign(sc_ipc_t ipc, sc_faddr_t msg_addr,
        return ret;
 }
 
-int sc_seco_secvio_dgo_config(sc_ipc_t ipc, uint8_t id, uint8_t access,
-                              u32 *data)
+int sc_seco_secvio_config(sc_ipc_t ipc, u8 id, u8 access,
+                         u32 *data0, u32 *data1, u32 *data2, u32 *data3,
+                         u32 *data4, u8 size)
+{
+       struct udevice *dev = gd->arch.scu_dev;
+       struct sc_rpc_msg_s msg;
+       int msg_size = sizeof(struct sc_rpc_msg_s);
+       int ret;
+
+       RPC_VER(&msg) = SC_RPC_VERSION;
+       RPC_SIZE(&msg) = 7U;
+       RPC_SVC(&msg) = (u8)(SC_RPC_SVC_SECO);
+       RPC_FUNC(&msg) = (u8)(SECO_FUNC_SECVIO_CONFIG);
+
+       RPC_U32(&msg, 0U) = (u32)(*data0);
+       RPC_U32(&msg, 4U) = (u32)(*data1);
+       RPC_U32(&msg, 8U) = (u32)(*data2);
+       RPC_U32(&msg, 12U) = (u32)(*data3);
+       RPC_U32(&msg, 16U) = (u32)(*data4);
+       RPC_U8(&msg, 20U) = (u8)(id);
+       RPC_U8(&msg, 21U) = (u8)(access);
+       RPC_U8(&msg, 22U) = (u8)(size);
+
+       ret = misc_call(dev, SC_FALSE, &msg, msg_size, &msg, msg_size);
+       if (ret)
+               printf("%s, id:0x%x, access:%x, res:%d\n",
+                      __func__, id, access, RPC_R8(&msg));
+
+       *data0 = (u32)RPC_U32(&msg, 0U);
+       *data1 = (u32)RPC_U32(&msg, 4U);
+       *data2 = (u32)RPC_U32(&msg, 8U);
+       *data3 = (u32)RPC_U32(&msg, 12U);
+       *data4 = (u32)RPC_U32(&msg, 16U);
+
+       return ret;
+}
+
+int sc_seco_secvio_dgo_config(sc_ipc_t ipc, u8 id, u8 access, u32 *data)
 {
        struct udevice *dev = gd->arch.scu_dev;
        struct sc_rpc_msg_s msg;