1*0a7bc1c0SAndrey Smirnov /* 2*0a7bc1c0SAndrey Smirnov * IMX7 Secure Non-Volatile Storage 3*0a7bc1c0SAndrey Smirnov * 4*0a7bc1c0SAndrey Smirnov * Copyright (c) 2018, Impinj, Inc. 5*0a7bc1c0SAndrey Smirnov * 6*0a7bc1c0SAndrey Smirnov * Author: Andrey Smirnov <andrew.smirnov@gmail.com> 7*0a7bc1c0SAndrey Smirnov * 8*0a7bc1c0SAndrey Smirnov * This work is licensed under the terms of the GNU GPL, version 2 or later. 9*0a7bc1c0SAndrey Smirnov * See the COPYING file in the top-level directory. 10*0a7bc1c0SAndrey Smirnov * 11*0a7bc1c0SAndrey Smirnov * Bare minimum emulation code needed to support being able to shut 12*0a7bc1c0SAndrey Smirnov * down linux guest gracefully. 13*0a7bc1c0SAndrey Smirnov */ 14*0a7bc1c0SAndrey Smirnov 15*0a7bc1c0SAndrey Smirnov #include "qemu/osdep.h" 16*0a7bc1c0SAndrey Smirnov #include "hw/misc/imx7_snvs.h" 17*0a7bc1c0SAndrey Smirnov #include "qemu/log.h" 18*0a7bc1c0SAndrey Smirnov #include "sysemu/sysemu.h" 19*0a7bc1c0SAndrey Smirnov 20*0a7bc1c0SAndrey Smirnov static uint64_t imx7_snvs_read(void *opaque, hwaddr offset, unsigned size) 21*0a7bc1c0SAndrey Smirnov { 22*0a7bc1c0SAndrey Smirnov return 0; 23*0a7bc1c0SAndrey Smirnov } 24*0a7bc1c0SAndrey Smirnov 25*0a7bc1c0SAndrey Smirnov static void imx7_snvs_write(void *opaque, hwaddr offset, 26*0a7bc1c0SAndrey Smirnov uint64_t v, unsigned size) 27*0a7bc1c0SAndrey Smirnov { 28*0a7bc1c0SAndrey Smirnov const uint32_t value = v; 29*0a7bc1c0SAndrey Smirnov const uint32_t mask = SNVS_LPCR_TOP | SNVS_LPCR_DP_EN; 30*0a7bc1c0SAndrey Smirnov 31*0a7bc1c0SAndrey Smirnov if (offset == SNVS_LPCR && ((value & mask) == mask)) { 32*0a7bc1c0SAndrey Smirnov qemu_system_shutdown_request(SHUTDOWN_CAUSE_GUEST_SHUTDOWN); 33*0a7bc1c0SAndrey Smirnov } 34*0a7bc1c0SAndrey Smirnov } 35*0a7bc1c0SAndrey Smirnov 36*0a7bc1c0SAndrey Smirnov static const struct MemoryRegionOps imx7_snvs_ops = { 37*0a7bc1c0SAndrey Smirnov .read = imx7_snvs_read, 38*0a7bc1c0SAndrey Smirnov .write = imx7_snvs_write, 39*0a7bc1c0SAndrey Smirnov .endianness = DEVICE_NATIVE_ENDIAN, 40*0a7bc1c0SAndrey Smirnov .impl = { 41*0a7bc1c0SAndrey Smirnov /* 42*0a7bc1c0SAndrey Smirnov * Our device would not work correctly if the guest was doing 43*0a7bc1c0SAndrey Smirnov * unaligned access. This might not be a limitation on the real 44*0a7bc1c0SAndrey Smirnov * device but in practice there is no reason for a guest to access 45*0a7bc1c0SAndrey Smirnov * this device unaligned. 46*0a7bc1c0SAndrey Smirnov */ 47*0a7bc1c0SAndrey Smirnov .min_access_size = 4, 48*0a7bc1c0SAndrey Smirnov .max_access_size = 4, 49*0a7bc1c0SAndrey Smirnov .unaligned = false, 50*0a7bc1c0SAndrey Smirnov }, 51*0a7bc1c0SAndrey Smirnov }; 52*0a7bc1c0SAndrey Smirnov 53*0a7bc1c0SAndrey Smirnov static void imx7_snvs_init(Object *obj) 54*0a7bc1c0SAndrey Smirnov { 55*0a7bc1c0SAndrey Smirnov SysBusDevice *sd = SYS_BUS_DEVICE(obj); 56*0a7bc1c0SAndrey Smirnov IMX7SNVSState *s = IMX7_SNVS(obj); 57*0a7bc1c0SAndrey Smirnov 58*0a7bc1c0SAndrey Smirnov memory_region_init_io(&s->mmio, obj, &imx7_snvs_ops, s, 59*0a7bc1c0SAndrey Smirnov TYPE_IMX7_SNVS, 0x1000); 60*0a7bc1c0SAndrey Smirnov 61*0a7bc1c0SAndrey Smirnov sysbus_init_mmio(sd, &s->mmio); 62*0a7bc1c0SAndrey Smirnov } 63*0a7bc1c0SAndrey Smirnov 64*0a7bc1c0SAndrey Smirnov static void imx7_snvs_class_init(ObjectClass *klass, void *data) 65*0a7bc1c0SAndrey Smirnov { 66*0a7bc1c0SAndrey Smirnov DeviceClass *dc = DEVICE_CLASS(klass); 67*0a7bc1c0SAndrey Smirnov 68*0a7bc1c0SAndrey Smirnov dc->desc = "i.MX7 Secure Non-Volatile Storage Module"; 69*0a7bc1c0SAndrey Smirnov } 70*0a7bc1c0SAndrey Smirnov 71*0a7bc1c0SAndrey Smirnov static const TypeInfo imx7_snvs_info = { 72*0a7bc1c0SAndrey Smirnov .name = TYPE_IMX7_SNVS, 73*0a7bc1c0SAndrey Smirnov .parent = TYPE_SYS_BUS_DEVICE, 74*0a7bc1c0SAndrey Smirnov .instance_size = sizeof(IMX7SNVSState), 75*0a7bc1c0SAndrey Smirnov .instance_init = imx7_snvs_init, 76*0a7bc1c0SAndrey Smirnov .class_init = imx7_snvs_class_init, 77*0a7bc1c0SAndrey Smirnov }; 78*0a7bc1c0SAndrey Smirnov 79*0a7bc1c0SAndrey Smirnov static void imx7_snvs_register_type(void) 80*0a7bc1c0SAndrey Smirnov { 81*0a7bc1c0SAndrey Smirnov type_register_static(&imx7_snvs_info); 82*0a7bc1c0SAndrey Smirnov } 83*0a7bc1c0SAndrey Smirnov type_init(imx7_snvs_register_type) 84