xref: /openbmc/qemu/hw/misc/mchp_pfsoc_ioscb.c (revision b492a4b8)
1 /*
2  * Microchip PolarFire SoC IOSCB module emulation
3  *
4  * Copyright (c) 2020 Wind River Systems, Inc.
5  *
6  * Author:
7  *   Bin Meng <bin.meng@windriver.com>
8  *
9  * This program is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU General Public License as
11  * published by the Free Software Foundation; either version 2 or
12  * (at your option) version 3 of the License.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "qemu/osdep.h"
24 #include "qemu/bitops.h"
25 #include "qemu/log.h"
26 #include "qapi/error.h"
27 #include "hw/hw.h"
28 #include "hw/sysbus.h"
29 #include "hw/misc/mchp_pfsoc_ioscb.h"
30 
31 /*
32  * The whole IOSCB module registers map into the system address at 0x3000_0000,
33  * named as "System Port 0 (AXI-D0)".
34  */
35 #define IOSCB_WHOLE_REG_SIZE        0x10000000
36 #define IOSCB_SUBMOD_REG_SIZE       0x1000
37 
38 /*
39  * There are many sub-modules in the IOSCB module.
40  * See Microchip PolarFire SoC documentation (Register_Map.zip),
41  * Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm
42  *
43  * The following are sub-modules offsets that are of concern.
44  */
45 #define IOSCB_LANE01_BASE           0x06500000
46 #define IOSCB_LANE23_BASE           0x06510000
47 #define IOSCB_CTRL_BASE             0x07020000
48 #define IOSCB_CFG_BASE              0x07080000
49 #define IOSCB_PLL_MSS_BASE          0x0E001000
50 #define IOSCB_CFM_MSS_BASE          0x0E002000
51 #define IOSCB_PLL_DDR_BASE          0x0E010000
52 #define IOSCB_BC_DDR_BASE           0x0E020000
53 #define IOSCB_IO_CALIB_DDR_BASE     0x0E040000
54 #define IOSCB_PLL_SGMII_BASE        0x0E080000
55 #define IOSCB_DLL_SGMII_BASE        0x0E100000
56 #define IOSCB_CFM_SGMII_BASE        0x0E200000
57 #define IOSCB_BC_SGMII_BASE         0x0E400000
58 #define IOSCB_IO_CALIB_SGMII_BASE   0x0E800000
59 
60 static uint64_t mchp_pfsoc_dummy_read(void *opaque, hwaddr offset,
61                                       unsigned size)
62 {
63     qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
64                   "(size %d, offset 0x%" HWADDR_PRIx ")\n",
65                   __func__, size, offset);
66 
67     return 0;
68 }
69 
70 static void mchp_pfsoc_dummy_write(void *opaque, hwaddr offset,
71                                    uint64_t value, unsigned size)
72 {
73     qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
74                   "(size %d, value 0x%" PRIx64
75                   ", offset 0x%" HWADDR_PRIx ")\n",
76                   __func__, size, value, offset);
77 }
78 
79 static const MemoryRegionOps mchp_pfsoc_dummy_ops = {
80     .read = mchp_pfsoc_dummy_read,
81     .write = mchp_pfsoc_dummy_write,
82     .endianness = DEVICE_LITTLE_ENDIAN,
83 };
84 
85 /* All PLL modules in IOSCB have the same register layout */
86 
87 #define PLL_CTRL    0x04
88 
89 static uint64_t mchp_pfsoc_pll_read(void *opaque, hwaddr offset,
90                                     unsigned size)
91 {
92     uint32_t val = 0;
93 
94     switch (offset) {
95     case PLL_CTRL:
96         /* PLL is locked */
97         val = BIT(25);
98         break;
99     default:
100         qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
101                       "(size %d, offset 0x%" HWADDR_PRIx ")\n",
102                       __func__, size, offset);
103         break;
104     }
105 
106     return val;
107 }
108 
109 static const MemoryRegionOps mchp_pfsoc_pll_ops = {
110     .read = mchp_pfsoc_pll_read,
111     .write = mchp_pfsoc_dummy_write,
112     .endianness = DEVICE_LITTLE_ENDIAN,
113 };
114 
115 /* IO_CALIB_DDR submodule */
116 
117 #define IO_CALIB_DDR_IOC_REG1   0x08
118 
119 static uint64_t mchp_pfsoc_io_calib_ddr_read(void *opaque, hwaddr offset,
120                                              unsigned size)
121 {
122     uint32_t val = 0;
123 
124     switch (offset) {
125     case IO_CALIB_DDR_IOC_REG1:
126         /* calibration completed */
127         val = BIT(2);
128         break;
129     default:
130         qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
131                       "(size %d, offset 0x%" HWADDR_PRIx ")\n",
132                       __func__, size, offset);
133         break;
134     }
135 
136     return val;
137 }
138 
139 static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops = {
140     .read = mchp_pfsoc_io_calib_ddr_read,
141     .write = mchp_pfsoc_dummy_write,
142     .endianness = DEVICE_LITTLE_ENDIAN,
143 };
144 
145 static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp)
146 {
147     MchpPfSoCIoscbState *s = MCHP_PFSOC_IOSCB(dev);
148     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
149 
150     memory_region_init(&s->container, OBJECT(s),
151                        "mchp.pfsoc.ioscb", IOSCB_WHOLE_REG_SIZE);
152     sysbus_init_mmio(sbd, &s->container);
153 
154     /* add subregions for all sub-modules in IOSCB */
155 
156     memory_region_init_io(&s->lane01, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
157                           "mchp.pfsoc.ioscb.lane01", IOSCB_SUBMOD_REG_SIZE);
158     memory_region_add_subregion(&s->container, IOSCB_LANE01_BASE, &s->lane01);
159 
160     memory_region_init_io(&s->lane23, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
161                           "mchp.pfsoc.ioscb.lane23", IOSCB_SUBMOD_REG_SIZE);
162     memory_region_add_subregion(&s->container, IOSCB_LANE23_BASE, &s->lane23);
163 
164     memory_region_init_io(&s->ctrl, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
165                           "mchp.pfsoc.ioscb.ctrl", IOSCB_SUBMOD_REG_SIZE);
166     memory_region_add_subregion(&s->container, IOSCB_CTRL_BASE, &s->ctrl);
167 
168     memory_region_init_io(&s->cfg, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
169                           "mchp.pfsoc.ioscb.cfg", IOSCB_SUBMOD_REG_SIZE);
170     memory_region_add_subregion(&s->container, IOSCB_CFG_BASE, &s->cfg);
171 
172     memory_region_init_io(&s->pll_mss, OBJECT(s), &mchp_pfsoc_pll_ops, s,
173                           "mchp.pfsoc.ioscb.pll_mss", IOSCB_SUBMOD_REG_SIZE);
174     memory_region_add_subregion(&s->container, IOSCB_PLL_MSS_BASE, &s->pll_mss);
175 
176     memory_region_init_io(&s->cfm_mss, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
177                           "mchp.pfsoc.ioscb.cfm_mss", IOSCB_SUBMOD_REG_SIZE);
178     memory_region_add_subregion(&s->container, IOSCB_CFM_MSS_BASE, &s->cfm_mss);
179 
180     memory_region_init_io(&s->pll_ddr, OBJECT(s), &mchp_pfsoc_pll_ops, s,
181                           "mchp.pfsoc.ioscb.pll_ddr", IOSCB_SUBMOD_REG_SIZE);
182     memory_region_add_subregion(&s->container, IOSCB_PLL_DDR_BASE, &s->pll_ddr);
183 
184     memory_region_init_io(&s->bc_ddr, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
185                           "mchp.pfsoc.ioscb.bc_ddr", IOSCB_SUBMOD_REG_SIZE);
186     memory_region_add_subregion(&s->container, IOSCB_BC_DDR_BASE, &s->bc_ddr);
187 
188     memory_region_init_io(&s->io_calib_ddr, OBJECT(s),
189                           &mchp_pfsoc_io_calib_ddr_ops, s,
190                           "mchp.pfsoc.ioscb.io_calib_ddr",
191                           IOSCB_SUBMOD_REG_SIZE);
192     memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_DDR_BASE,
193                                 &s->io_calib_ddr);
194 
195     memory_region_init_io(&s->pll_sgmii, OBJECT(s), &mchp_pfsoc_pll_ops, s,
196                           "mchp.pfsoc.ioscb.pll_sgmii", IOSCB_SUBMOD_REG_SIZE);
197     memory_region_add_subregion(&s->container, IOSCB_PLL_SGMII_BASE,
198                                 &s->pll_sgmii);
199 
200     memory_region_init_io(&s->dll_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
201                           "mchp.pfsoc.ioscb.dll_sgmii", IOSCB_SUBMOD_REG_SIZE);
202     memory_region_add_subregion(&s->container, IOSCB_DLL_SGMII_BASE,
203                                 &s->dll_sgmii);
204 
205     memory_region_init_io(&s->cfm_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
206                           "mchp.pfsoc.ioscb.cfm_sgmii", IOSCB_SUBMOD_REG_SIZE);
207     memory_region_add_subregion(&s->container, IOSCB_CFM_SGMII_BASE,
208                                 &s->cfm_sgmii);
209 
210     memory_region_init_io(&s->bc_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s,
211                           "mchp.pfsoc.ioscb.bc_sgmii", IOSCB_SUBMOD_REG_SIZE);
212     memory_region_add_subregion(&s->container, IOSCB_BC_SGMII_BASE,
213                                 &s->bc_sgmii);
214 
215     memory_region_init_io(&s->io_calib_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops,
216                           s, "mchp.pfsoc.ioscb.io_calib_sgmii",
217                           IOSCB_SUBMOD_REG_SIZE);
218     memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_SGMII_BASE,
219                                 &s->io_calib_sgmii);
220 }
221 
222 static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, void *data)
223 {
224     DeviceClass *dc = DEVICE_CLASS(klass);
225 
226     dc->desc = "Microchip PolarFire SoC IOSCB modules";
227     dc->realize = mchp_pfsoc_ioscb_realize;
228 }
229 
230 static const TypeInfo mchp_pfsoc_ioscb_info = {
231     .name          = TYPE_MCHP_PFSOC_IOSCB,
232     .parent        = TYPE_SYS_BUS_DEVICE,
233     .instance_size = sizeof(MchpPfSoCIoscbState),
234     .class_init    = mchp_pfsoc_ioscb_class_init,
235 };
236 
237 static void mchp_pfsoc_ioscb_register_types(void)
238 {
239     type_register_static(&mchp_pfsoc_ioscb_info);
240 }
241 
242 type_init(mchp_pfsoc_ioscb_register_types)
243