1 | /* |
2 | * Copyright (c) 2018, Impinj, Inc. |
3 | * |
4 | * i.MX7 GPR IP block emulation code |
5 | * |
6 | * Author: Andrey Smirnov <andrew.smirnov@gmail.com> |
7 | * |
8 | * This work is licensed under the terms of the GNU GPL, version 2 or later. |
9 | * See the COPYING file in the top-level directory. |
10 | * |
11 | * Bare minimum emulation code needed to support being able to shut |
12 | * down linux guest gracefully. |
13 | */ |
14 | |
15 | #include "qemu/osdep.h" |
16 | #include "hw/misc/imx7_gpr.h" |
17 | #include "qemu/log.h" |
18 | #include "qemu/module.h" |
19 | |
20 | #include "trace.h" |
21 | |
22 | enum IMX7GPRRegisters { |
23 | IOMUXC_GPR0 = 0x00, |
24 | IOMUXC_GPR1 = 0x04, |
25 | IOMUXC_GPR2 = 0x08, |
26 | IOMUXC_GPR3 = 0x0c, |
27 | IOMUXC_GPR4 = 0x10, |
28 | IOMUXC_GPR5 = 0x14, |
29 | IOMUXC_GPR6 = 0x18, |
30 | IOMUXC_GPR7 = 0x1c, |
31 | IOMUXC_GPR8 = 0x20, |
32 | IOMUXC_GPR9 = 0x24, |
33 | IOMUXC_GPR10 = 0x28, |
34 | IOMUXC_GPR11 = 0x2c, |
35 | IOMUXC_GPR12 = 0x30, |
36 | IOMUXC_GPR13 = 0x34, |
37 | IOMUXC_GPR14 = 0x38, |
38 | IOMUXC_GPR15 = 0x3c, |
39 | IOMUXC_GPR16 = 0x40, |
40 | IOMUXC_GPR17 = 0x44, |
41 | IOMUXC_GPR18 = 0x48, |
42 | IOMUXC_GPR19 = 0x4c, |
43 | IOMUXC_GPR20 = 0x50, |
44 | IOMUXC_GPR21 = 0x54, |
45 | IOMUXC_GPR22 = 0x58, |
46 | }; |
47 | |
48 | #define IMX7D_GPR1_IRQ_MASK BIT(12) |
49 | #define IMX7D_GPR1_ENET1_TX_CLK_SEL_MASK BIT(13) |
50 | #define IMX7D_GPR1_ENET2_TX_CLK_SEL_MASK BIT(14) |
51 | #define IMX7D_GPR1_ENET_TX_CLK_SEL_MASK (0x3 << 13) |
52 | #define IMX7D_GPR1_ENET1_CLK_DIR_MASK BIT(17) |
53 | #define IMX7D_GPR1_ENET2_CLK_DIR_MASK BIT(18) |
54 | #define IMX7D_GPR1_ENET_CLK_DIR_MASK (0x3 << 17) |
55 | |
56 | #define IMX7D_GPR5_CSI_MUX_CONTROL_MIPI BIT(4) |
57 | #define IMX7D_GPR12_PCIE_PHY_REFCLK_SEL BIT(5) |
58 | #define IMX7D_GPR22_PCIE_PHY_PLL_LOCKED BIT(31) |
59 | |
60 | |
61 | static uint64_t imx7_gpr_read(void *opaque, hwaddr offset, unsigned size) |
62 | { |
63 | trace_imx7_gpr_read(offset); |
64 | |
65 | if (offset == IOMUXC_GPR22) { |
66 | return IMX7D_GPR22_PCIE_PHY_PLL_LOCKED; |
67 | } |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | static void imx7_gpr_write(void *opaque, hwaddr offset, |
73 | uint64_t v, unsigned size) |
74 | { |
75 | trace_imx7_gpr_write(offset, v); |
76 | } |
77 | |
78 | static const struct MemoryRegionOps imx7_gpr_ops = { |
79 | .read = imx7_gpr_read, |
80 | .write = imx7_gpr_write, |
81 | .endianness = DEVICE_NATIVE_ENDIAN, |
82 | .impl = { |
83 | /* |
84 | * Our device would not work correctly if the guest was doing |
85 | * unaligned access. This might not be a limitation on the |
86 | * real device but in practice there is no reason for a guest |
87 | * to access this device unaligned. |
88 | */ |
89 | .min_access_size = 4, |
90 | .max_access_size = 4, |
91 | .unaligned = false, |
92 | }, |
93 | }; |
94 | |
95 | static void imx7_gpr_init(Object *obj) |
96 | { |
97 | SysBusDevice *sd = SYS_BUS_DEVICE(obj); |
98 | IMX7GPRState *s = IMX7_GPR(obj); |
99 | |
100 | memory_region_init_io(&s->mmio, obj, &imx7_gpr_ops, s, |
101 | TYPE_IMX7_GPR, 64 * 1024); |
102 | sysbus_init_mmio(sd, &s->mmio); |
103 | } |
104 | |
105 | static void imx7_gpr_class_init(ObjectClass *klass, void *data) |
106 | { |
107 | DeviceClass *dc = DEVICE_CLASS(klass); |
108 | |
109 | dc->desc = "i.MX7 General Purpose Registers Module" ; |
110 | } |
111 | |
112 | static const TypeInfo imx7_gpr_info = { |
113 | .name = TYPE_IMX7_GPR, |
114 | .parent = TYPE_SYS_BUS_DEVICE, |
115 | .instance_size = sizeof(IMX7GPRState), |
116 | .instance_init = imx7_gpr_init, |
117 | .class_init = imx7_gpr_class_init, |
118 | }; |
119 | |
120 | static void imx7_gpr_register_type(void) |
121 | { |
122 | type_register_static(&imx7_gpr_info); |
123 | } |
124 | type_init(imx7_gpr_register_type) |
125 | |