xref: /qemu/hw/misc/npcm_gcr.c (revision 12d1a768bdfea6e27a3a829228840d72507613a1)
1 /*
2  * Nuvoton NPCM7xx/8xx System Global Control Registers.
3  *
4  * Copyright 2020 Google LLC
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14  * for more details.
15  */
16 
17 #include "qemu/osdep.h"
18 
19 #include "hw/misc/npcm_gcr.h"
20 #include "hw/qdev-properties.h"
21 #include "migration/vmstate.h"
22 #include "qapi/error.h"
23 #include "qemu/cutils.h"
24 #include "qemu/log.h"
25 #include "qemu/module.h"
26 #include "qemu/units.h"
27 
28 #include "trace.h"
29 
30 #define NPCM7XX_GCR_MIN_DRAM_SIZE   (128 * MiB)
31 #define NPCM7XX_GCR_MAX_DRAM_SIZE   (2 * GiB)
32 
33 enum NPCM7xxGCRRegisters {
34     NPCM7XX_GCR_PDID,
35     NPCM7XX_GCR_PWRON,
36     NPCM7XX_GCR_MFSEL1          = 0x0c / sizeof(uint32_t),
37     NPCM7XX_GCR_MFSEL2,
38     NPCM7XX_GCR_MISCPE,
39     NPCM7XX_GCR_SPSWC           = 0x038 / sizeof(uint32_t),
40     NPCM7XX_GCR_INTCR,
41     NPCM7XX_GCR_INTSR,
42     NPCM7XX_GCR_HIFCR           = 0x050 / sizeof(uint32_t),
43     NPCM7XX_GCR_INTCR2          = 0x060 / sizeof(uint32_t),
44     NPCM7XX_GCR_MFSEL3,
45     NPCM7XX_GCR_SRCNT,
46     NPCM7XX_GCR_RESSR,
47     NPCM7XX_GCR_RLOCKR1,
48     NPCM7XX_GCR_FLOCKR1,
49     NPCM7XX_GCR_DSCNT,
50     NPCM7XX_GCR_MDLR,
51     NPCM7XX_GCR_SCRPAD3,
52     NPCM7XX_GCR_SCRPAD2,
53     NPCM7XX_GCR_DAVCLVLR        = 0x098 / sizeof(uint32_t),
54     NPCM7XX_GCR_INTCR3,
55     NPCM7XX_GCR_VSINTR          = 0x0ac / sizeof(uint32_t),
56     NPCM7XX_GCR_MFSEL4,
57     NPCM7XX_GCR_CPBPNTR         = 0x0c4 / sizeof(uint32_t),
58     NPCM7XX_GCR_CPCTL           = 0x0d0 / sizeof(uint32_t),
59     NPCM7XX_GCR_CP2BST,
60     NPCM7XX_GCR_B2CPNT,
61     NPCM7XX_GCR_CPPCTL,
62     NPCM7XX_GCR_I2CSEGSEL,
63     NPCM7XX_GCR_I2CSEGCTL,
64     NPCM7XX_GCR_VSRCR,
65     NPCM7XX_GCR_MLOCKR,
66     NPCM7XX_GCR_SCRPAD          = 0x013c / sizeof(uint32_t),
67     NPCM7XX_GCR_USB1PHYCTL,
68     NPCM7XX_GCR_USB2PHYCTL,
69 };
70 
71 static const uint32_t npcm7xx_cold_reset_values[NPCM7XX_GCR_NR_REGS] = {
72     [NPCM7XX_GCR_PDID]          = 0x04a92750,   /* Poleg A1 */
73     [NPCM7XX_GCR_MISCPE]        = 0x0000ffff,
74     [NPCM7XX_GCR_SPSWC]         = 0x00000003,
75     [NPCM7XX_GCR_INTCR]         = 0x0000035e,
76     [NPCM7XX_GCR_HIFCR]         = 0x0000004e,
77     [NPCM7XX_GCR_INTCR2]        = (1U << 19),   /* DDR initialized */
78     [NPCM7XX_GCR_RESSR]         = 0x80000000,
79     [NPCM7XX_GCR_DSCNT]         = 0x000000c0,
80     [NPCM7XX_GCR_DAVCLVLR]      = 0x5a00f3cf,
81     [NPCM7XX_GCR_SCRPAD]        = 0x00000008,
82     [NPCM7XX_GCR_USB1PHYCTL]    = 0x034730e4,
83     [NPCM7XX_GCR_USB2PHYCTL]    = 0x034730e4,
84 };
85 
86 enum NPCM8xxGCRRegisters {
87     NPCM8XX_GCR_PDID,
88     NPCM8XX_GCR_PWRON,
89     NPCM8XX_GCR_MISCPE          = 0x014 / sizeof(uint32_t),
90     NPCM8XX_GCR_FLOCKR2         = 0x020 / sizeof(uint32_t),
91     NPCM8XX_GCR_FLOCKR3,
92     NPCM8XX_GCR_A35_MODE        = 0x034 / sizeof(uint32_t),
93     NPCM8XX_GCR_SPSWC,
94     NPCM8XX_GCR_INTCR,
95     NPCM8XX_GCR_INTSR,
96     NPCM8XX_GCR_HIFCR           = 0x050 / sizeof(uint32_t),
97     NPCM8XX_GCR_INTCR2          = 0x060 / sizeof(uint32_t),
98     NPCM8XX_GCR_SRCNT           = 0x068 / sizeof(uint32_t),
99     NPCM8XX_GCR_RESSR,
100     NPCM8XX_GCR_RLOCKR1,
101     NPCM8XX_GCR_FLOCKR1,
102     NPCM8XX_GCR_DSCNT,
103     NPCM8XX_GCR_MDLR,
104     NPCM8XX_GCR_SCRPAD_C        = 0x080 / sizeof(uint32_t),
105     NPCM8XX_GCR_SCRPAD_B,
106     NPCM8XX_GCR_DAVCLVLR        = 0x098 / sizeof(uint32_t),
107     NPCM8XX_GCR_INTCR3,
108     NPCM8XX_GCR_PCIRCTL         = 0x0a0 / sizeof(uint32_t),
109     NPCM8XX_GCR_VSINTR,
110     NPCM8XX_GCR_SD2SUR1         = 0x0b4 / sizeof(uint32_t),
111     NPCM8XX_GCR_SD2SUR2,
112     NPCM8XX_GCR_INTCR4          = 0x0c0 / sizeof(uint32_t),
113     NPCM8XX_GCR_CPCTL           = 0x0d0 / sizeof(uint32_t),
114     NPCM8XX_GCR_CP2BST,
115     NPCM8XX_GCR_B2CPNT,
116     NPCM8XX_GCR_CPPCTL,
117     NPCM8XX_GCR_I2CSEGSEL       = 0x0e0 / sizeof(uint32_t),
118     NPCM8XX_GCR_I2CSEGCTL,
119     NPCM8XX_GCR_VSRCR,
120     NPCM8XX_GCR_MLOCKR,
121     NPCM8XX_GCR_SCRPAD          = 0x13c / sizeof(uint32_t),
122     NPCM8XX_GCR_USB1PHYCTL,
123     NPCM8XX_GCR_USB2PHYCTL,
124     NPCM8XX_GCR_USB3PHYCTL,
125     NPCM8XX_GCR_MFSEL1          = 0x260 / sizeof(uint32_t),
126     NPCM8XX_GCR_MFSEL2,
127     NPCM8XX_GCR_MFSEL3,
128     NPCM8XX_GCR_MFSEL4,
129     NPCM8XX_GCR_MFSEL5,
130     NPCM8XX_GCR_MFSEL6,
131     NPCM8XX_GCR_MFSEL7,
132     NPCM8XX_GCR_MFSEL_LK1       = 0x280 / sizeof(uint32_t),
133     NPCM8XX_GCR_MFSEL_LK2,
134     NPCM8XX_GCR_MFSEL_LK3,
135     NPCM8XX_GCR_MFSEL_LK4,
136     NPCM8XX_GCR_MFSEL_LK5,
137     NPCM8XX_GCR_MFSEL_LK6,
138     NPCM8XX_GCR_MFSEL_LK7,
139     NPCM8XX_GCR_MFSEL_SET1      = 0x2a0 / sizeof(uint32_t),
140     NPCM8XX_GCR_MFSEL_SET2,
141     NPCM8XX_GCR_MFSEL_SET3,
142     NPCM8XX_GCR_MFSEL_SET4,
143     NPCM8XX_GCR_MFSEL_SET5,
144     NPCM8XX_GCR_MFSEL_SET6,
145     NPCM8XX_GCR_MFSEL_SET7,
146     NPCM8XX_GCR_MFSEL_CLR1      = 0x2c0 / sizeof(uint32_t),
147     NPCM8XX_GCR_MFSEL_CLR2,
148     NPCM8XX_GCR_MFSEL_CLR3,
149     NPCM8XX_GCR_MFSEL_CLR4,
150     NPCM8XX_GCR_MFSEL_CLR5,
151     NPCM8XX_GCR_MFSEL_CLR6,
152     NPCM8XX_GCR_MFSEL_CLR7,
153     NPCM8XX_GCR_WD0RCRLK        = 0x400 / sizeof(uint32_t),
154     NPCM8XX_GCR_WD1RCRLK,
155     NPCM8XX_GCR_WD2RCRLK,
156     NPCM8XX_GCR_SWRSTC1LK,
157     NPCM8XX_GCR_SWRSTC2LK,
158     NPCM8XX_GCR_SWRSTC3LK,
159     NPCM8XX_GCR_TIPRSTCLK,
160     NPCM8XX_GCR_CORSTCLK,
161     NPCM8XX_GCR_WD0RCRBLK,
162     NPCM8XX_GCR_WD1RCRBLK,
163     NPCM8XX_GCR_WD2RCRBLK,
164     NPCM8XX_GCR_SWRSTC1BLK,
165     NPCM8XX_GCR_SWRSTC2BLK,
166     NPCM8XX_GCR_SWRSTC3BLK,
167     NPCM8XX_GCR_TIPRSTCBLK,
168     NPCM8XX_GCR_CORSTCBLK,
169     /* 64 scratch pad registers start here. 0xe00 ~ 0xefc */
170     NPCM8XX_GCR_SCRPAD_00       = 0xe00 / sizeof(uint32_t),
171     /* 32 semaphore registers start here. 0xf00 ~ 0xf7c */
172     NPCM8XX_GCR_GP_SEMFR_00     = 0xf00 / sizeof(uint32_t),
173     NPCM8XX_GCR_GP_SEMFR_31     = 0xf7c / sizeof(uint32_t),
174 };
175 
176 static const uint32_t npcm8xx_cold_reset_values[NPCM8XX_GCR_NR_REGS] = {
177     [NPCM8XX_GCR_PDID]          = 0x04a35850,   /* Arbel A1 */
178     [NPCM8XX_GCR_MISCPE]        = 0x0000ffff,
179     [NPCM8XX_GCR_A35_MODE]      = 0xfff4ff30,
180     [NPCM8XX_GCR_SPSWC]         = 0x00000003,
181     [NPCM8XX_GCR_INTCR]         = 0x0010035e,
182     [NPCM8XX_GCR_HIFCR]         = 0x0000004e,
183     [NPCM8XX_GCR_SD2SUR1]       = 0xfdc80000,
184     [NPCM8XX_GCR_SD2SUR2]       = 0x5200b130,
185     [NPCM8XX_GCR_INTCR2]        = (1U << 19),   /* DDR initialized */
186     [NPCM8XX_GCR_RESSR]         = 0x80000000,
187     [NPCM8XX_GCR_DAVCLVLR]      = 0x5a00f3cf,
188     [NPCM8XX_GCR_INTCR3]        = 0x5e001002,
189     [NPCM8XX_GCR_VSRCR]         = 0x00004800,
190     [NPCM8XX_GCR_SCRPAD]        = 0x00000008,
191     [NPCM8XX_GCR_USB1PHYCTL]    = 0x034730e4,
192     [NPCM8XX_GCR_USB2PHYCTL]    = 0x034730e4,
193     [NPCM8XX_GCR_USB3PHYCTL]    = 0x034730e4,
194     /* All 32 semaphores should be initialized to 1. */
195     [NPCM8XX_GCR_GP_SEMFR_00...NPCM8XX_GCR_GP_SEMFR_31] = 0x00000001,
196 };
197 
npcm_gcr_read(void * opaque,hwaddr offset,unsigned size)198 static uint64_t npcm_gcr_read(void *opaque, hwaddr offset, unsigned size)
199 {
200     uint32_t reg = offset / sizeof(uint32_t);
201     NPCMGCRState *s = opaque;
202     NPCMGCRClass *c = NPCM_GCR_GET_CLASS(s);
203     uint64_t value;
204 
205     if (reg >= c->nr_regs) {
206         qemu_log_mask(LOG_GUEST_ERROR,
207                       "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
208                       __func__, offset);
209         return 0;
210     }
211 
212     switch (size) {
213     case 4:
214         value = s->regs[reg];
215         break;
216 
217     case 8:
218         g_assert(!(reg & 1));
219         value = deposit64(s->regs[reg], 32, 32, s->regs[reg + 1]);
220         break;
221 
222     default:
223         g_assert_not_reached();
224     }
225 
226     trace_npcm_gcr_read(offset, value);
227     return value;
228 }
229 
npcm_gcr_write(void * opaque,hwaddr offset,uint64_t v,unsigned size)230 static void npcm_gcr_write(void *opaque, hwaddr offset,
231                               uint64_t v, unsigned size)
232 {
233     uint32_t reg = offset / sizeof(uint32_t);
234     NPCMGCRState *s = opaque;
235     NPCMGCRClass *c = NPCM_GCR_GET_CLASS(s);
236     uint32_t value = v;
237 
238     trace_npcm_gcr_write(offset, v);
239 
240     if (reg >= c->nr_regs) {
241         qemu_log_mask(LOG_GUEST_ERROR,
242                       "%s: offset 0x%04" HWADDR_PRIx " out of range\n",
243                       __func__, offset);
244         return;
245     }
246 
247     switch (size) {
248     case 4:
249         switch (reg) {
250         case NPCM7XX_GCR_PDID:
251         case NPCM7XX_GCR_PWRON:
252         case NPCM7XX_GCR_INTSR:
253             qemu_log_mask(LOG_GUEST_ERROR,
254                           "%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
255                           __func__, offset);
256             return;
257 
258         case NPCM7XX_GCR_RESSR:
259         case NPCM7XX_GCR_CP2BST:
260             /* Write 1 to clear */
261             value = s->regs[reg] & ~value;
262             break;
263 
264         case NPCM7XX_GCR_RLOCKR1:
265         case NPCM7XX_GCR_MDLR:
266             /* Write 1 to set */
267             value |= s->regs[reg];
268             break;
269         };
270         s->regs[reg] = value;
271         break;
272 
273     case 8:
274         g_assert(!(reg & 1));
275         s->regs[reg] = value;
276         s->regs[reg + 1] = extract64(v, 32, 32);
277         break;
278 
279     default:
280         g_assert_not_reached();
281     }
282 }
283 
npcm_gcr_check_mem_op(void * opaque,hwaddr offset,unsigned size,bool is_write,MemTxAttrs attrs)284 static bool npcm_gcr_check_mem_op(void *opaque, hwaddr offset,
285                                   unsigned size, bool is_write,
286                                   MemTxAttrs attrs)
287 {
288     NPCMGCRClass *c = NPCM_GCR_GET_CLASS(opaque);
289 
290     if (offset >= c->nr_regs * sizeof(uint32_t)) {
291         return false;
292     }
293 
294     switch (size) {
295     case 4:
296         return true;
297     case 8:
298         if (offset >= NPCM8XX_GCR_SCRPAD_00 * sizeof(uint32_t) &&
299             offset < (NPCM8XX_GCR_NR_REGS - 1) * sizeof(uint32_t)) {
300             return true;
301         } else {
302             return false;
303         }
304     default:
305         return false;
306     }
307 }
308 
309 static const struct MemoryRegionOps npcm_gcr_ops = {
310     .read       = npcm_gcr_read,
311     .write      = npcm_gcr_write,
312     .endianness = DEVICE_LITTLE_ENDIAN,
313     .valid      = {
314         .min_access_size        = 4,
315         .max_access_size        = 8,
316         .accepts                = npcm_gcr_check_mem_op,
317         .unaligned              = false,
318     },
319 };
320 
npcm7xx_gcr_enter_reset(Object * obj,ResetType type)321 static void npcm7xx_gcr_enter_reset(Object *obj, ResetType type)
322 {
323     NPCMGCRState *s = NPCM_GCR(obj);
324     NPCMGCRClass *c = NPCM_GCR_GET_CLASS(obj);
325 
326     g_assert(sizeof(s->regs) >= sizeof(c->cold_reset_values));
327     g_assert(sizeof(s->regs) >= c->nr_regs * sizeof(uint32_t));
328     memcpy(s->regs, c->cold_reset_values, c->nr_regs * sizeof(uint32_t));
329     /* These 3 registers are at the same location in both 7xx and 8xx. */
330     s->regs[NPCM7XX_GCR_PWRON] = s->reset_pwron;
331     s->regs[NPCM7XX_GCR_MDLR] = s->reset_mdlr;
332     s->regs[NPCM7XX_GCR_INTCR3] = s->reset_intcr3;
333 }
334 
npcm8xx_gcr_enter_reset(Object * obj,ResetType type)335 static void npcm8xx_gcr_enter_reset(Object *obj, ResetType type)
336 {
337     NPCMGCRState *s = NPCM_GCR(obj);
338     NPCMGCRClass *c = NPCM_GCR_GET_CLASS(obj);
339 
340     memcpy(s->regs, c->cold_reset_values, c->nr_regs * sizeof(uint32_t));
341     /* These 3 registers are at the same location in both 7xx and 8xx. */
342     s->regs[NPCM8XX_GCR_PWRON] = s->reset_pwron;
343     s->regs[NPCM8XX_GCR_MDLR] = s->reset_mdlr;
344     s->regs[NPCM8XX_GCR_INTCR3] = s->reset_intcr3;
345     s->regs[NPCM8XX_GCR_SCRPAD_B] = s->reset_scrpad_b;
346 }
347 
npcm_gcr_realize(DeviceState * dev,Error ** errp)348 static void npcm_gcr_realize(DeviceState *dev, Error **errp)
349 {
350     ERRP_GUARD();
351     NPCMGCRState *s = NPCM_GCR(dev);
352     uint64_t dram_size;
353     Object *obj;
354 
355     obj = object_property_get_link(OBJECT(dev), "dram-mr", errp);
356     if (!obj) {
357         error_prepend(errp, "%s: required dram-mr link not found: ", __func__);
358         return;
359     }
360     dram_size = memory_region_size(MEMORY_REGION(obj));
361     if (!is_power_of_2(dram_size) ||
362         dram_size < NPCM7XX_GCR_MIN_DRAM_SIZE ||
363         dram_size > NPCM7XX_GCR_MAX_DRAM_SIZE) {
364         g_autofree char *sz = size_to_str(dram_size);
365         g_autofree char *min_sz = size_to_str(NPCM7XX_GCR_MIN_DRAM_SIZE);
366         g_autofree char *max_sz = size_to_str(NPCM7XX_GCR_MAX_DRAM_SIZE);
367         error_setg(errp, "%s: unsupported DRAM size %s", __func__, sz);
368         error_append_hint(errp,
369                           "DRAM size must be a power of two between %s and %s,"
370                           " inclusive.\n", min_sz, max_sz);
371         return;
372     }
373 
374     /* Power-on reset value */
375     s->reset_intcr3 = 0x00001002;
376 
377     /*
378      * The GMMAP (Graphics Memory Map) field is used by u-boot to detect the
379      * DRAM size, and is normally initialized by the boot block as part of DRAM
380      * training. However, since we don't have a complete emulation of the
381      * memory controller and try to make it look like it has already been
382      * initialized, the boot block will skip this initialization, and we need
383      * to make sure this field is set correctly up front.
384      *
385      * WARNING: some versions of u-boot only looks at bits 8 and 9, so 2 GiB of
386      * DRAM will be interpreted as 128 MiB.
387      *
388      * https://github.com/Nuvoton-Israel/u-boot/blob/2aef993bd2aafeb5408dbaad0f3ce099ee40c4aa/board/nuvoton/poleg/poleg.c#L244
389      */
390     s->reset_intcr3 |= ctz64(dram_size / NPCM7XX_GCR_MIN_DRAM_SIZE) << 8;
391 
392     /*
393      * The boot block starting from 0.0.6 for NPCM8xx SoCs stores the DRAM size
394      * in the SCRPAD2 registers. We need to set this field correctly since
395      * the initialization is skipped as we mentioned above.
396      * https://github.com/Nuvoton-Israel/u-boot/blob/npcm8mnx-v2019.01_tmp/board/nuvoton/arbel/arbel.c#L737
397      */
398     s->reset_scrpad_b = dram_size;
399 }
400 
npcm_gcr_init(Object * obj)401 static void npcm_gcr_init(Object *obj)
402 {
403     NPCMGCRState *s = NPCM_GCR(obj);
404 
405     memory_region_init_io(&s->iomem, obj, &npcm_gcr_ops, s,
406                           TYPE_NPCM_GCR, 4 * KiB);
407     sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
408 }
409 
410 static const VMStateDescription vmstate_npcm_gcr = {
411     .name = "npcm-gcr",
412     .version_id = 2,
413     .minimum_version_id = 2,
414     .fields = (const VMStateField[]) {
415         VMSTATE_UINT32_ARRAY(regs, NPCMGCRState, NPCM_GCR_MAX_NR_REGS),
416         VMSTATE_END_OF_LIST(),
417     },
418 };
419 
420 static const Property npcm_gcr_properties[] = {
421     DEFINE_PROP_UINT32("disabled-modules", NPCMGCRState, reset_mdlr, 0),
422     DEFINE_PROP_UINT32("power-on-straps", NPCMGCRState, reset_pwron, 0),
423 };
424 
npcm_gcr_class_init(ObjectClass * klass,const void * data)425 static void npcm_gcr_class_init(ObjectClass *klass, const void *data)
426 {
427     DeviceClass *dc = DEVICE_CLASS(klass);
428 
429     dc->realize = npcm_gcr_realize;
430     dc->vmsd = &vmstate_npcm_gcr;
431 
432     device_class_set_props(dc, npcm_gcr_properties);
433 }
434 
npcm7xx_gcr_class_init(ObjectClass * klass,const void * data)435 static void npcm7xx_gcr_class_init(ObjectClass *klass, const void *data)
436 {
437     NPCMGCRClass *c = NPCM_GCR_CLASS(klass);
438     DeviceClass *dc = DEVICE_CLASS(klass);
439     ResettableClass *rc = RESETTABLE_CLASS(klass);
440 
441     dc->desc = "NPCM7xx System Global Control Registers";
442     rc->phases.enter = npcm7xx_gcr_enter_reset;
443 
444     c->nr_regs = NPCM7XX_GCR_NR_REGS;
445     c->cold_reset_values = npcm7xx_cold_reset_values;
446     rc->phases.enter = npcm7xx_gcr_enter_reset;
447 }
448 
npcm8xx_gcr_class_init(ObjectClass * klass,const void * data)449 static void npcm8xx_gcr_class_init(ObjectClass *klass, const void *data)
450 {
451     NPCMGCRClass *c = NPCM_GCR_CLASS(klass);
452     DeviceClass *dc = DEVICE_CLASS(klass);
453     ResettableClass *rc = RESETTABLE_CLASS(klass);
454 
455     dc->desc = "NPCM8xx System Global Control Registers";
456     c->nr_regs = NPCM8XX_GCR_NR_REGS;
457     c->cold_reset_values = npcm8xx_cold_reset_values;
458     rc->phases.enter = npcm8xx_gcr_enter_reset;
459 }
460 
461 static const TypeInfo npcm_gcr_info[] = {
462     {
463         .name               = TYPE_NPCM_GCR,
464         .parent             = TYPE_SYS_BUS_DEVICE,
465         .instance_size      = sizeof(NPCMGCRState),
466         .instance_init      = npcm_gcr_init,
467         .class_size         = sizeof(NPCMGCRClass),
468         .class_init         = npcm_gcr_class_init,
469         .abstract           = true,
470     },
471     {
472         .name               = TYPE_NPCM7XX_GCR,
473         .parent             = TYPE_NPCM_GCR,
474         .class_init         = npcm7xx_gcr_class_init,
475     },
476     {
477         .name               = TYPE_NPCM8XX_GCR,
478         .parent             = TYPE_NPCM_GCR,
479         .class_init         = npcm8xx_gcr_class_init,
480     },
481 };
482 DEFINE_TYPES(npcm_gcr_info)
483