• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revisión47faad96c3078255dc6db20bb4fc3d574433f068 (tree)
Tiempo2021-05-27 14:10:44
AutorYoshinori Sato <ysato@user...>
CommiterYoshinori Sato

Log Message

hw/sh4: sh7750 Add CPG.

CPG required new hw modules.

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>

Cambiar Resumen

Diferencia incremental

--- a/hw/sh4/meson.build
+++ b/hw/sh4/meson.build
@@ -2,6 +2,7 @@ sh4_ss = ss.source_set()
22 sh4_ss.add(files(
33 'sh7750.c',
44 'sh7750_regnames.c',
5+ 'sh7751-cpg.c',
56 ))
67 sh4_ss.add(when: 'CONFIG_R2D', if_true: files('r2d.c'))
78 sh4_ss.add(when: 'CONFIG_SHIX', if_true: files('shix.c'))
--- a/hw/sh4/sh7750.c
+++ b/hw/sh4/sh7750.c
@@ -24,6 +24,7 @@
2424 */
2525
2626 #include "qemu/osdep.h"
27+#include "qapi/error.h"
2728 #include "hw/irq.h"
2829 #include "hw/sh4/sh.h"
2930 #include "sysemu/sysemu.h"
@@ -32,6 +33,8 @@
3233 #include "hw/sh4/sh_intc.h"
3334 #include "hw/timer/tmu012.h"
3435 #include "exec/exec-all.h"
36+#include "hw/sh4/sh7751-cpg.h"
37+#include "hw/qdev-properties.h"
3538
3639 #define NB_DEVICES 4
3740
@@ -752,9 +755,29 @@ static const MemoryRegionOps sh7750_mmct_ops = {
752755 .endianness = DEVICE_NATIVE_ENDIAN,
753756 };
754757
758+static SH7751CPGBaseState *sh_cpg_init(MemoryRegion *sysmem,
759+ int cputype)
760+{
761+ const char *cpgtype;
762+ SH7751CPGBaseState *cpg;
763+ if (cputype & (SH_CPU_SH7750R | SH_CPU_SH7751R)) {
764+ cpgtype = TYPE_SH7751R_CPG;
765+ } else {
766+ cpgtype = TYPE_SH7751_CPG;
767+ }
768+ cpg = SH7751CPGBase(qdev_new(cpgtype));
769+ qdev_prop_set_uint32(DEVICE(cpg), "xtal-frequency-hz", 20 * 1000 * 1000);
770+ qdev_prop_set_uint32(DEVICE(cpg), "clock-mode", 5);
771+ sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 0, 0x1fc00000);
772+ sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 1, P4ADDR(0x1fc00000));
773+ sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 2, A7ADDR(0x1fc00000));
774+ return cpg;
775+}
776+
755777 SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
756778 {
757779 SH7750State *s;
780+ SH7751CPGBaseState *cpg;
758781
759782 s = g_malloc0(sizeof(SH7750State));
760783 s->cpu = cpu;
@@ -800,6 +823,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
800823
801824 cpu->env.intc_handle = &s->intc;
802825
826+ cpg = sh_cpg_init(sysmem, cpu->env.id);
803827 sh_serial_init(sysmem, 0x1fe00000,
804828 0, s->periph_freq, serial_hd(0),
805829 s->intc.irqs[SCI1_ERI],
@@ -824,6 +848,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
824848 s->intc.irqs[TMU2_TUNI],
825849 s->intc.irqs[TMU2_TICPI]);
826850
851+ sysbus_realize(SYS_BUS_DEVICE(cpg), &error_abort);
827852 if (cpu->env.id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) {
828853 sh_intc_register_sources(&s->intc,
829854 _INTC_ARRAY(vectors_dma4),
--- /dev/null
+++ b/hw/sh4/sh7751-cpg.c
@@ -0,0 +1,457 @@
1+/*
2+ * SH7750 / SH7751 Clock Generation Circuit
3+ *
4+ * Datasheet: SH7751 Group, SH7751R Group User's Manual: Hardware
5+ * (Rev.4.01 R01UH0457EJ0401)
6+ *
7+ * Copyright (c) 2020 Yoshinori Sato
8+ *
9+ * This program is free software; you can redistribute it and/or modify it
10+ * under the terms and conditions of the GNU General Public License,
11+ * version 2 or later, as published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope it will be useful, but WITHOUT
14+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16+ * more details.
17+ *
18+ * You should have received a copy of the GNU General Public License along with
19+ * this program. If not, see <http://www.gnu.org/licenses/>.
20+ */
21+
22+#include "qemu/osdep.h"
23+#include "qapi/error.h"
24+#include "qemu/log.h"
25+#include "hw/hw.h"
26+#include "hw/sh4/sh7751-cpg.h"
27+#include "hw/sysbus.h"
28+#include "hw/qdev-properties.h"
29+#include "hw/registerfields.h"
30+#include "hw/qdev-properties.h"
31+#include "hw/clock.h"
32+#include "migration/vmstate.h"
33+
34+#define SH7751_XTAL_MIN_HZ (1 * 1000 * 1000)
35+#define SH7751_XTAL_MAX_HZ (34 * 1000 * 1000)
36+
37+REG16(FREQCR, 0)
38+ FIELD(FREQCR, PFC, 0, 3)
39+ FIELD(FREQCR, BFC, 3, 3)
40+ FIELD(FREQCR, IFC, 6, 3)
41+ FIELD(FREQCR, PLL2EN, 9, 1)
42+ FIELD(FREQCR, PLL1EN, 10, 1)
43+ FIELD(FREQCR, CKOEN, 11, 1)
44+REG8(STBCR, 4)
45+REG8(STBCR2, 16)
46+
47+REG32(CLKSTP00, 0)
48+REG32(CLKSTPCLR00, 8)
49+
50+typedef struct {
51+ const char *name;
52+ int devnum;
53+ int reg;
54+ int offset;
55+} dev_clock_t;
56+
57+static const dev_clock_t dev_clock_list[] = {
58+ { .name = "pck_sci", .devnum = CK_SCI, .reg = 0, .offset = 0},
59+ { .name = "pck_rtc", .devnum = CK_RTC, .reg = 0, .offset = 1},
60+ { .name = "pck_tmu-0", .devnum = CK_TMU_0, .reg = 0, .offset = 2},
61+ { .name = "pck_scif", .devnum = CK_SCIF, .reg = 0, .offset = 3},
62+ { .name = "pck_dmac", .devnum = CK_DMAC, .reg = 0, .offset = 4},
63+ { .name = "pck_ubc", .devnum = CK_UBC, .reg = 1, .offset = 0},
64+ { .name = "pck_sq", .devnum = CK_SQ, .reg = 1, .offset = 1},
65+ { .name = "pck_intc", .devnum = CK_INTC, .reg = 2, .offset = 0},
66+ { .name = "pck_tmu-1", .devnum = CK_TMU_1, .reg = 2, .offset = 1},
67+ { .name = "pck_pcic", .devnum = CK_PCIC, .reg = 2, .offset = 2},
68+ { },
69+};
70+
71+static void set_clock_in(SH7751CPGBaseState *cpg, const dev_clock_t *ck)
72+{
73+ Clock *out;
74+ uint64_t period;
75+
76+ out = qdev_get_clock_out(DEVICE(cpg), ck->name);
77+ g_assert(out);
78+ period = 0;
79+ switch (ck->reg) {
80+ case 0:
81+ case 1:
82+ if (extract8(cpg->stbcr[ck->reg], ck->offset, 1) == 0) {
83+ period = clock_get(cpg->clk_ick);
84+ }
85+ break;
86+ case 2:
87+ if (extract32(cpg->clkstp00, ck->offset, 1) == 0) {
88+ period = clock_get(cpg->clk_ick);
89+ }
90+ break;
91+ }
92+ if (clock_get(out) != period) {
93+ clock_update(out, period);
94+ }
95+}
96+
97+static void update_divrate(SH7751CPGBaseState *cpg)
98+{
99+ SH7751CPGBaseClass *k = SH7751CPG_GET_CLASS(cpg);
100+ int ick = FIELD_EX32(cpg->freqcr, FREQCR, IFC);
101+ int bck = FIELD_EX32(cpg->freqcr, FREQCR, BFC);
102+ int pck = FIELD_EX32(cpg->freqcr, FREQCR, PFC);
103+ const dev_clock_t *p = dev_clock_list;
104+ uint32_t divinput;
105+
106+ divinput = cpg->xtal_freq_hz * k->pll1mul(cpg->clock_mode, cpg->freqcr);
107+
108+ ick = ick < 4 ? ick + 1 : (ick - 1) * 2;
109+ clock_update_hz(cpg->clk_ick, divinput / ick);
110+ bck = bck < 4 ? bck + 1 : (bck - 1) * 2;
111+ clock_update_hz(cpg->clk_bck, divinput / bck);
112+ pck = pck < 3 ? pck + 2 : pck * 2;
113+ clock_update_hz(cpg->clk_pck, divinput / pck);
114+
115+ while (p->name) {
116+ set_clock_in(cpg, p);
117+ p++;
118+ }
119+}
120+
121+static const dev_clock_t *find_clock_list(int crno, int bit)
122+{
123+ const dev_clock_t *ret = dev_clock_list;
124+ while (ret->name) {
125+ if (ret->reg == crno && ret->offset == bit) {
126+ return ret;
127+ }
128+ ret++;
129+ }
130+ return NULL;
131+}
132+
133+static void update_stbcr(SH7751CPGBaseState *cpg, int no, uint32_t diff)
134+{
135+ int bit = 0;
136+ const dev_clock_t *p;
137+ static const char *reg[] = {"STBCR", "STBCR2", "CLKSTP00"};
138+
139+ while (diff) {
140+ if (diff & 1) {
141+ p = find_clock_list(no, bit);
142+ if (p) {
143+ set_clock_in(cpg, p);
144+ } else {
145+ qemu_log_mask(LOG_UNIMP, "sh7751-cpg: %s "
146+ " bit %d is not implement.\n", reg[no], bit);
147+ }
148+ }
149+ bit++;
150+ diff >>= 1;
151+ }
152+}
153+
154+static uint64_t cpg_read(void *opaque, hwaddr addr, unsigned size)
155+{
156+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
157+ int reg;
158+
159+ switch (addr) {
160+ case A_FREQCR:
161+ if (size != 2) {
162+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
163+ HWADDR_PRIX " Invalid access size.\n", addr);
164+ return UINT64_MAX;
165+ }
166+ return cpg->freqcr;
167+ case A_STBCR:
168+ case A_STBCR2:
169+ if (size != 1) {
170+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
171+ HWADDR_PRIX " Invalid access size.\n", addr);
172+ return UINT64_MAX;
173+ }
174+ reg = extract32(addr, 4, 1); /* STBCR -> 0x04 / STBCR2 -> 0x10 */
175+ return cpg->stbcr[reg];
176+ break;
177+ default:
178+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
179+ HWADDR_PRIX " Invalid address.\n", addr);
180+ return UINT64_MAX;
181+ }
182+
183+}
184+
185+static void cpg_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
186+{
187+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
188+ uint32_t old_stbcr;
189+ int reg;
190+
191+ switch (addr) {
192+ case A_FREQCR:
193+ if (size != 2) {
194+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
195+ HWADDR_PRIX " Invalid access size.\n", addr);
196+ return;
197+ }
198+ if ((cpg->freqcr ^ val) & 0x0600) {
199+ qemu_log_mask(LOG_UNIMP,
200+ "sh7751-cpg: PLL operation not supported.\n");
201+ }
202+ cpg->freqcr = val;
203+ update_divrate(cpg);
204+ break;
205+ case A_STBCR:
206+ case A_STBCR2:
207+ if (size != 1) {
208+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
209+ HWADDR_PRIX " Invalid access size.\n", addr);
210+ return;
211+ }
212+ reg = extract32(addr, 4, 1); /* STBCR -> 0x04 / STBCR2 -> 0x10 */
213+ old_stbcr = cpg->stbcr[reg];
214+ old_stbcr ^= val;
215+ cpg->stbcr[reg] = val;
216+ update_stbcr(cpg, reg, old_stbcr);
217+ break;
218+ default:
219+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
220+ HWADDR_PRIX " Invalid address.\n", addr);
221+ }
222+}
223+
224+static uint64_t stp_read(void *opaque, hwaddr addr, unsigned size)
225+{
226+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
227+
228+ switch (addr) {
229+ case A_CLKSTP00:
230+ return cpg->clkstp00;
231+ case A_CLKSTPCLR00:
232+ qemu_log_mask(LOG_GUEST_ERROR,
233+ "sh7751-cpg: CLKSTPCLR00 is write only.\n");
234+ return UINT64_MAX;
235+ default:
236+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
237+ HWADDR_PRIX " Invalid address.\n", addr);
238+ return UINT64_MAX;
239+ }
240+}
241+
242+static void stp_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
243+{
244+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
245+
246+ val &= 0x7;
247+ switch (addr) {
248+ case A_CLKSTP00:
249+ cpg->clkstp00 |= val;
250+ update_stbcr(cpg, 2, val);
251+ break;
252+ case A_CLKSTPCLR00:
253+ cpg->clkstp00 &= ~val;
254+ update_stbcr(cpg, 2, val);
255+ break;
256+ default:
257+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
258+ HWADDR_PRIX " Invalid address.\n", addr);
259+ }
260+}
261+
262+static int sh7751_pll1mul(int mode, uint16_t freqcr)
263+{
264+ int div1;
265+ int pll1;
266+ switch (mode) {
267+ case 3:
268+ case 5:
269+ case 6:
270+ div1 = 2;
271+ break;
272+ default:
273+ div1 = 1;
274+ }
275+ if (FIELD_EX16(freqcr, FREQCR, PLL1EN)) {
276+ pll1 = 6;
277+ } else {
278+ pll1 = 1;
279+ }
280+ return pll1 / div1;
281+}
282+
283+static int sh7751r_pll1mul(int mode, uint16_t freqcr)
284+{
285+ int pll1;
286+ switch (mode) {
287+ case 0:
288+ case 1:
289+ case 3:
290+ case 5:
291+ pll1 = 12;
292+ break;
293+ case 2:
294+ case 4:
295+ case 6:
296+ pll1 = 6;
297+ break;
298+ default:
299+ g_assert_not_reached();
300+ }
301+ if (!FIELD_EX16(freqcr, FREQCR, PLL1EN)) {
302+ pll1 = 1;
303+ }
304+ return pll1;
305+}
306+
307+static const MemoryRegionOps cpg_ops = {
308+ .write = cpg_write,
309+ .read = cpg_read,
310+ .endianness = DEVICE_NATIVE_ENDIAN,
311+ .impl = {
312+ .min_access_size = 1,
313+ .max_access_size = 4,
314+ },
315+};
316+
317+static const MemoryRegionOps stp_ops = {
318+ .write = stp_write,
319+ .read = stp_read,
320+ .endianness = DEVICE_NATIVE_ENDIAN,
321+ .impl = {
322+ .min_access_size = 4,
323+ .max_access_size = 4,
324+ },
325+};
326+
327+static const ClockPortInitArray sh7751_cpg_clocks = {
328+ QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_ick),
329+ QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_bck),
330+ QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_pck),
331+ QDEV_CLOCK_END
332+};
333+
334+static void sh7751cpg_realize(DeviceState *dev, Error **errp)
335+{
336+ SH7751CPGBaseState *cpg = SH7751CPGBase(dev);
337+ SH7751CPGBaseClass *k = SH7751CPG_GET_CLASS(cpg);
338+
339+ if (cpg->xtal_freq_hz == 0) {
340+ error_setg(errp, "\"xtal-frequency-hz\" property must be provided.");
341+ return;
342+ }
343+ /* XTAL range: 1-34 MHz */
344+ if (cpg->xtal_freq_hz < SH7751_XTAL_MIN_HZ ||
345+ cpg->xtal_freq_hz > SH7751_XTAL_MAX_HZ) {
346+ error_setg(errp, "\"xtal-frequency-hz\" property in incorrect range.");
347+ return;
348+ }
349+ /* Clock mode: 0 - 6 */
350+ if (cpg->clock_mode > 6) {
351+ error_setg(errp, "\"clock-mode\" property in incorrect range.");
352+ return;
353+ }
354+
355+ cpg->freqcr = k->initfreqcr[cpg->clock_mode];
356+ update_divrate(cpg);
357+}
358+
359+static void sh7751_cpg_init(Object *obj)
360+{
361+ SH7751CPGBaseState *cpg = SH7751CPGBase(obj);
362+ const dev_clock_t *p = dev_clock_list;
363+ qdev_init_clocks(DEVICE(obj), sh7751_cpg_clocks);
364+ /* connect parent clock */
365+ while (p->name) {
366+ cpg->dev_clocks[p->devnum] = qdev_init_clock_out(DEVICE(obj),
367+ p->name);
368+ p++;
369+ }
370+
371+ memory_region_init_io(&cpg->memory[0], OBJECT(cpg), &cpg_ops,
372+ cpg, "sh7751-cpg", 0x14);
373+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[0]);
374+ memory_region_init_alias(&cpg->memory[1], NULL,
375+ "sh7751-cpg-a4", &cpg->memory[0], 0, 0x14);
376+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[1]);
377+ memory_region_init_alias(&cpg->memory[2], NULL,
378+ "sh7751-cpg-p7", &cpg->memory[0], 0, 0x14);
379+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[2]);
380+ memory_region_init_io(&cpg->memory[3], OBJECT(cpg), &stp_ops,
381+ cpg, "sh7751-stp", 0x10);
382+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[3]);
383+ memory_region_init_alias(&cpg->memory[4], NULL,
384+ "sh7751-stp-a4", &cpg->memory[3], 0, 0x10);
385+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[4]);
386+ memory_region_init_alias(&cpg->memory[5], NULL,
387+ "sh7751-stp-p7", &cpg->memory[3], 0, 0x10u);
388+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[5]);
389+}
390+
391+static Property sh7751_cpg_properties[] = {
392+ DEFINE_PROP_UINT32("xtal-frequency-hz",
393+ SH7751CPGBaseState, xtal_freq_hz, 0),
394+ DEFINE_PROP_UINT32("clock-mode",
395+ SH7751CPGBaseState, clock_mode, 0),
396+ DEFINE_PROP_END_OF_LIST(),
397+};
398+
399+static void sh7751cpg_base_class_init(ObjectClass *klass, void *data)
400+{
401+ DeviceClass *dc = DEVICE_CLASS(klass);
402+
403+ device_class_set_props(dc, sh7751_cpg_properties);
404+}
405+
406+static void sh7751cpg_class_init(ObjectClass *klass, void *data)
407+{
408+ SH7751CPGBaseClass *base = SH7751CPGBaseClass(klass);
409+ DeviceClass *dc = DEVICE_CLASS(klass);
410+ static uint16_t initfreqcr[] = {0x0e1a, 0x0e23, 0x0e13, 0x0e13,
411+ 0x0e0a, 0x0e0a, 0x0808};
412+
413+ base->pll1mul = sh7751_pll1mul;
414+ base->initfreqcr = initfreqcr;
415+ dc->realize = sh7751cpg_realize;
416+}
417+
418+static void sh7751rcpg_class_init(ObjectClass *klass, void *data)
419+{
420+ SH7751CPGBaseClass *base = SH7751CPGBaseClass(klass);
421+ DeviceClass *dc = DEVICE_CLASS(klass);
422+ static uint16_t initfreqcr[] = {0x0e1a, 0x0e2c, 0x0e13, 0x0e13,
423+ 0x0e0a, 0x0e0a, 0x0808};
424+
425+ base->pll1mul = sh7751r_pll1mul;
426+ base->initfreqcr = initfreqcr;
427+ dc->realize = sh7751cpg_realize;
428+}
429+
430+static const TypeInfo sh7751cpg_info[] = {
431+ {
432+ .name = TYPE_SH7751_CPG_BASE,
433+ .parent = TYPE_SYS_BUS_DEVICE,
434+ .instance_size = sizeof(SH7751CPGBaseState),
435+ .class_init = sh7751cpg_base_class_init,
436+ .class_size = sizeof(SH7751CPGBaseClass),
437+ .abstract = true,
438+ },
439+ {
440+ .name = TYPE_SH7751_CPG,
441+ .parent = TYPE_SH7751_CPG_BASE,
442+ .instance_size = sizeof(SH7751CPGState),
443+ .instance_init = sh7751_cpg_init,
444+ .class_init = sh7751cpg_class_init,
445+ .class_size = sizeof(SH7751CPGClass),
446+ },
447+ {
448+ .name = TYPE_SH7751R_CPG,
449+ .parent = TYPE_SH7751_CPG_BASE,
450+ .instance_size = sizeof(SH7751RCPGState),
451+ .instance_init = sh7751_cpg_init,
452+ .class_init = sh7751rcpg_class_init,
453+ .class_size = sizeof(SH7751RCPGClass),
454+ },
455+};
456+
457+DEFINE_TYPES(sh7751cpg_info)
--- /dev/null
+++ b/include/hw/sh4/sh7751-cpg.h
@@ -0,0 +1,94 @@
1+/*
2+ * SH7751(R) Clock generator circuit
3+ *
4+ * Datasheet: SH7751 Group, SH7751R Group User's Manual: Hardware
5+ * (Rev.4.01 R01UH0457EJ0401)
6+ *
7+ * Copyright (c) 2020 Yoshinori Sato
8+ *
9+ * This program is free software; you can redistribute it and/or modify it
10+ * under the terms and conditions of the GNU General Public License,
11+ * version 2 or later, as published by the Free Software Foundation.
12+ *
13+ * This program is distributed in the hope it will be useful, but WITHOUT
14+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16+ * more details.
17+ *
18+ * You should have received a copy of the GNU General Public License along with
19+ * this program. If not, see <http://www.gnu.org/licenses/>.
20+ */
21+
22+#ifndef HW_SH4_SH7751_CPG_H
23+#define HW_SH4_SH7751_CPG_H
24+
25+#include "hw/sysbus.h"
26+#include "hw/qdev-clock.h"
27+
28+#define TYPE_SH7751_CPG_BASE "sh7751-cpg-base"
29+#define SH7751CPGBase(obj) \
30+ OBJECT_CHECK(SH7751CPGBaseState, (obj), TYPE_SH7751_CPG_BASE)
31+#define TYPE_SH7751_CPG "sh7751-cpg"
32+#define SH7751CPG(obj) OBJECT_CHECK(SH7751CPGState, (obj), TYPE_SH7751_CPG)
33+#define TYPE_SH7751R_CPG "sh7751r-cpg"
34+#define SH7751RCPG(obj) OBJECT_CHECK(SH7751RCPGState, (obj), TYPE_SH7751R_CPG)
35+#define SH7751CPG_GET_CLASS(obj) \
36+ OBJECT_GET_CLASS(SH7751CPGBaseClass, obj, TYPE_SH7751_CPG_BASE)
37+#define SH7751CPGBaseClass(klass) \
38+ OBJECT_CLASS_CHECK(SH7751CPGBaseClass, klass, TYPE_SH7751_CPG_BASE)
39+
40+enum {
41+ CK_DMAC,
42+ CK_SCIF,
43+ CK_TMU_0,
44+ CK_RTC,
45+ CK_SCI,
46+ CK_SQ,
47+ CK_UBC,
48+ CK_PCIC,
49+ CK_TMU_1,
50+ CK_INTC,
51+ NUM_SUBCLOCK,
52+};
53+
54+typedef struct SH7751CPGBaseState {
55+ SysBusDevice parent_obj;
56+ uint8_t stbcr[2];
57+ uint32_t clkstp00;
58+ uint16_t freqcr;
59+
60+ uint32_t clock_mode;
61+ int ick;
62+ Clock *clk_ick;
63+ int bck;
64+ Clock *clk_bck;
65+ int pck;
66+ Clock *clk_pck;
67+ Clock *dev_clocks[NUM_SUBCLOCK];
68+ uint32_t xtal_freq_hz;
69+ MemoryRegion memory[3 * 2];
70+} SH7751CPGBaseState;
71+
72+typedef struct {
73+ SH7751CPGBaseState parent_obj;
74+} SH7751CPGState;
75+
76+typedef struct {
77+ SH7751CPGBaseState parent_obj;
78+} SH7751RCPGState;
79+
80+typedef struct {
81+ SysBusDeviceClass parent;
82+ int (*pll1mul)(int mode, uint16_t freqcr);
83+ uint16_t *initfreqcr;
84+} SH7751CPGBaseClass;
85+
86+typedef struct {
87+ SH7751CPGBaseClass parent;
88+} SH7751CPGClass;
89+
90+typedef struct {
91+ SH7751CPGBaseClass parent;
92+} SH7751RCPGClass;
93+
94+#endif