From: Yoshinori Sato <ysato@users.sourceforge.jp>
To: qemu-devel@nongnu.org
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Subject: [PATCH 09/11] hw/sh4: sh7750 Add CPG.
Date: Thu, 27 May 2021 14:21:20 +0900 [thread overview]
Message-ID: <20210527052122.97103-10-ysato@users.sourceforge.jp> (raw)
In-Reply-To: <20210527052122.97103-1-ysato@users.sourceforge.jp>
CPG required new hw modules.
Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
---
include/hw/sh4/sh7751-cpg.h | 94 ++++++++
hw/sh4/sh7750.c | 25 ++
hw/sh4/sh7751-cpg.c | 457 ++++++++++++++++++++++++++++++++++++
hw/sh4/meson.build | 1 +
4 files changed, 577 insertions(+)
create mode 100644 include/hw/sh4/sh7751-cpg.h
create mode 100644 hw/sh4/sh7751-cpg.c
diff --git a/include/hw/sh4/sh7751-cpg.h b/include/hw/sh4/sh7751-cpg.h
new file mode 100644
index 0000000000..79f9abe210
--- /dev/null
+++ b/include/hw/sh4/sh7751-cpg.h
@@ -0,0 +1,94 @@
+/*
+ * SH7751(R) Clock generator circuit
+ *
+ * Datasheet: SH7751 Group, SH7751R Group User's Manual: Hardware
+ * (Rev.4.01 R01UH0457EJ0401)
+ *
+ * Copyright (c) 2020 Yoshinori Sato
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HW_SH4_SH7751_CPG_H
+#define HW_SH4_SH7751_CPG_H
+
+#include "hw/sysbus.h"
+#include "hw/qdev-clock.h"
+
+#define TYPE_SH7751_CPG_BASE "sh7751-cpg-base"
+#define SH7751CPGBase(obj) \
+ OBJECT_CHECK(SH7751CPGBaseState, (obj), TYPE_SH7751_CPG_BASE)
+#define TYPE_SH7751_CPG "sh7751-cpg"
+#define SH7751CPG(obj) OBJECT_CHECK(SH7751CPGState, (obj), TYPE_SH7751_CPG)
+#define TYPE_SH7751R_CPG "sh7751r-cpg"
+#define SH7751RCPG(obj) OBJECT_CHECK(SH7751RCPGState, (obj), TYPE_SH7751R_CPG)
+#define SH7751CPG_GET_CLASS(obj) \
+ OBJECT_GET_CLASS(SH7751CPGBaseClass, obj, TYPE_SH7751_CPG_BASE)
+#define SH7751CPGBaseClass(klass) \
+ OBJECT_CLASS_CHECK(SH7751CPGBaseClass, klass, TYPE_SH7751_CPG_BASE)
+
+enum {
+ CK_DMAC,
+ CK_SCIF,
+ CK_TMU_0,
+ CK_RTC,
+ CK_SCI,
+ CK_SQ,
+ CK_UBC,
+ CK_PCIC,
+ CK_TMU_1,
+ CK_INTC,
+ NUM_SUBCLOCK,
+};
+
+typedef struct SH7751CPGBaseState {
+ SysBusDevice parent_obj;
+ uint8_t stbcr[2];
+ uint32_t clkstp00;
+ uint16_t freqcr;
+
+ uint32_t clock_mode;
+ int ick;
+ Clock *clk_ick;
+ int bck;
+ Clock *clk_bck;
+ int pck;
+ Clock *clk_pck;
+ Clock *dev_clocks[NUM_SUBCLOCK];
+ uint32_t xtal_freq_hz;
+ MemoryRegion memory[3 * 2];
+} SH7751CPGBaseState;
+
+typedef struct {
+ SH7751CPGBaseState parent_obj;
+} SH7751CPGState;
+
+typedef struct {
+ SH7751CPGBaseState parent_obj;
+} SH7751RCPGState;
+
+typedef struct {
+ SysBusDeviceClass parent;
+ int (*pll1mul)(int mode, uint16_t freqcr);
+ uint16_t *initfreqcr;
+} SH7751CPGBaseClass;
+
+typedef struct {
+ SH7751CPGBaseClass parent;
+} SH7751CPGClass;
+
+typedef struct {
+ SH7751CPGBaseClass parent;
+} SH7751RCPGClass;
+
+#endif
diff --git a/hw/sh4/sh7750.c b/hw/sh4/sh7750.c
index d53a436d8c..2f6c382aa6 100644
--- a/hw/sh4/sh7750.c
+++ b/hw/sh4/sh7750.c
@@ -24,6 +24,7 @@
*/
#include "qemu/osdep.h"
+#include "qapi/error.h"
#include "hw/irq.h"
#include "hw/sh4/sh.h"
#include "sysemu/sysemu.h"
@@ -32,6 +33,8 @@
#include "hw/sh4/sh_intc.h"
#include "hw/timer/tmu012.h"
#include "exec/exec-all.h"
+#include "hw/sh4/sh7751-cpg.h"
+#include "hw/qdev-properties.h"
#define NB_DEVICES 4
@@ -752,9 +755,29 @@ static const MemoryRegionOps sh7750_mmct_ops = {
.endianness = DEVICE_NATIVE_ENDIAN,
};
+static SH7751CPGBaseState *sh_cpg_init(MemoryRegion *sysmem,
+ int cputype)
+{
+ const char *cpgtype;
+ SH7751CPGBaseState *cpg;
+ if (cputype & (SH_CPU_SH7750R | SH_CPU_SH7751R)) {
+ cpgtype = TYPE_SH7751R_CPG;
+ } else {
+ cpgtype = TYPE_SH7751_CPG;
+ }
+ cpg = SH7751CPGBase(qdev_new(cpgtype));
+ qdev_prop_set_uint32(DEVICE(cpg), "xtal-frequency-hz", 20 * 1000 * 1000);
+ qdev_prop_set_uint32(DEVICE(cpg), "clock-mode", 5);
+ sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 0, 0x1fc00000);
+ sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 1, P4ADDR(0x1fc00000));
+ sysbus_mmio_map(SYS_BUS_DEVICE(cpg), 2, A7ADDR(0x1fc00000));
+ return cpg;
+}
+
SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
{
SH7750State *s;
+ SH7751CPGBaseState *cpg;
s = g_malloc0(sizeof(SH7750State));
s->cpu = cpu;
@@ -800,6 +823,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
cpu->env.intc_handle = &s->intc;
+ cpg = sh_cpg_init(sysmem, cpu->env.id);
sh_serial_init(sysmem, 0x1fe00000,
0, s->periph_freq, serial_hd(0),
s->intc.irqs[SCI1_ERI],
@@ -824,6 +848,7 @@ SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
s->intc.irqs[TMU2_TUNI],
s->intc.irqs[TMU2_TICPI]);
+ sysbus_realize(SYS_BUS_DEVICE(cpg), &error_abort);
if (cpu->env.id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) {
sh_intc_register_sources(&s->intc,
_INTC_ARRAY(vectors_dma4),
diff --git a/hw/sh4/sh7751-cpg.c b/hw/sh4/sh7751-cpg.c
new file mode 100644
index 0000000000..4e057908ff
--- /dev/null
+++ b/hw/sh4/sh7751-cpg.c
@@ -0,0 +1,457 @@
+/*
+ * SH7750 / SH7751 Clock Generation Circuit
+ *
+ * Datasheet: SH7751 Group, SH7751R Group User's Manual: Hardware
+ * (Rev.4.01 R01UH0457EJ0401)
+ *
+ * Copyright (c) 2020 Yoshinori Sato
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2 or later, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "qemu/osdep.h"
+#include "qapi/error.h"
+#include "qemu/log.h"
+#include "hw/hw.h"
+#include "hw/sh4/sh7751-cpg.h"
+#include "hw/sysbus.h"
+#include "hw/qdev-properties.h"
+#include "hw/registerfields.h"
+#include "hw/qdev-properties.h"
+#include "hw/clock.h"
+#include "migration/vmstate.h"
+
+#define SH7751_XTAL_MIN_HZ (1 * 1000 * 1000)
+#define SH7751_XTAL_MAX_HZ (34 * 1000 * 1000)
+
+REG16(FREQCR, 0)
+ FIELD(FREQCR, PFC, 0, 3)
+ FIELD(FREQCR, BFC, 3, 3)
+ FIELD(FREQCR, IFC, 6, 3)
+ FIELD(FREQCR, PLL2EN, 9, 1)
+ FIELD(FREQCR, PLL1EN, 10, 1)
+ FIELD(FREQCR, CKOEN, 11, 1)
+REG8(STBCR, 4)
+REG8(STBCR2, 16)
+
+REG32(CLKSTP00, 0)
+REG32(CLKSTPCLR00, 8)
+
+typedef struct {
+ const char *name;
+ int devnum;
+ int reg;
+ int offset;
+} dev_clock_t;
+
+static const dev_clock_t dev_clock_list[] = {
+ { .name = "pck_sci", .devnum = CK_SCI, .reg = 0, .offset = 0},
+ { .name = "pck_rtc", .devnum = CK_RTC, .reg = 0, .offset = 1},
+ { .name = "pck_tmu-0", .devnum = CK_TMU_0, .reg = 0, .offset = 2},
+ { .name = "pck_scif", .devnum = CK_SCIF, .reg = 0, .offset = 3},
+ { .name = "pck_dmac", .devnum = CK_DMAC, .reg = 0, .offset = 4},
+ { .name = "pck_ubc", .devnum = CK_UBC, .reg = 1, .offset = 0},
+ { .name = "pck_sq", .devnum = CK_SQ, .reg = 1, .offset = 1},
+ { .name = "pck_intc", .devnum = CK_INTC, .reg = 2, .offset = 0},
+ { .name = "pck_tmu-1", .devnum = CK_TMU_1, .reg = 2, .offset = 1},
+ { .name = "pck_pcic", .devnum = CK_PCIC, .reg = 2, .offset = 2},
+ { },
+};
+
+static void set_clock_in(SH7751CPGBaseState *cpg, const dev_clock_t *ck)
+{
+ Clock *out;
+ uint64_t period;
+
+ out = qdev_get_clock_out(DEVICE(cpg), ck->name);
+ g_assert(out);
+ period = 0;
+ switch (ck->reg) {
+ case 0:
+ case 1:
+ if (extract8(cpg->stbcr[ck->reg], ck->offset, 1) == 0) {
+ period = clock_get(cpg->clk_ick);
+ }
+ break;
+ case 2:
+ if (extract32(cpg->clkstp00, ck->offset, 1) == 0) {
+ period = clock_get(cpg->clk_ick);
+ }
+ break;
+ }
+ if (clock_get(out) != period) {
+ clock_update(out, period);
+ }
+}
+
+static void update_divrate(SH7751CPGBaseState *cpg)
+{
+ SH7751CPGBaseClass *k = SH7751CPG_GET_CLASS(cpg);
+ int ick = FIELD_EX32(cpg->freqcr, FREQCR, IFC);
+ int bck = FIELD_EX32(cpg->freqcr, FREQCR, BFC);
+ int pck = FIELD_EX32(cpg->freqcr, FREQCR, PFC);
+ const dev_clock_t *p = dev_clock_list;
+ uint32_t divinput;
+
+ divinput = cpg->xtal_freq_hz * k->pll1mul(cpg->clock_mode, cpg->freqcr);
+
+ ick = ick < 4 ? ick + 1 : (ick - 1) * 2;
+ clock_update_hz(cpg->clk_ick, divinput / ick);
+ bck = bck < 4 ? bck + 1 : (bck - 1) * 2;
+ clock_update_hz(cpg->clk_bck, divinput / bck);
+ pck = pck < 3 ? pck + 2 : pck * 2;
+ clock_update_hz(cpg->clk_pck, divinput / pck);
+
+ while (p->name) {
+ set_clock_in(cpg, p);
+ p++;
+ }
+}
+
+static const dev_clock_t *find_clock_list(int crno, int bit)
+{
+ const dev_clock_t *ret = dev_clock_list;
+ while (ret->name) {
+ if (ret->reg == crno && ret->offset == bit) {
+ return ret;
+ }
+ ret++;
+ }
+ return NULL;
+}
+
+static void update_stbcr(SH7751CPGBaseState *cpg, int no, uint32_t diff)
+{
+ int bit = 0;
+ const dev_clock_t *p;
+ static const char *reg[] = {"STBCR", "STBCR2", "CLKSTP00"};
+
+ while (diff) {
+ if (diff & 1) {
+ p = find_clock_list(no, bit);
+ if (p) {
+ set_clock_in(cpg, p);
+ } else {
+ qemu_log_mask(LOG_UNIMP, "sh7751-cpg: %s "
+ " bit %d is not implement.\n", reg[no], bit);
+ }
+ }
+ bit++;
+ diff >>= 1;
+ }
+}
+
+static uint64_t cpg_read(void *opaque, hwaddr addr, unsigned size)
+{
+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
+ int reg;
+
+ switch (addr) {
+ case A_FREQCR:
+ if (size != 2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid access size.\n", addr);
+ return UINT64_MAX;
+ }
+ return cpg->freqcr;
+ case A_STBCR:
+ case A_STBCR2:
+ if (size != 1) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid access size.\n", addr);
+ return UINT64_MAX;
+ }
+ reg = extract32(addr, 4, 1); /* STBCR -> 0x04 / STBCR2 -> 0x10 */
+ return cpg->stbcr[reg];
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid address.\n", addr);
+ return UINT64_MAX;
+ }
+
+}
+
+static void cpg_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
+ uint32_t old_stbcr;
+ int reg;
+
+ switch (addr) {
+ case A_FREQCR:
+ if (size != 2) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid access size.\n", addr);
+ return;
+ }
+ if ((cpg->freqcr ^ val) & 0x0600) {
+ qemu_log_mask(LOG_UNIMP,
+ "sh7751-cpg: PLL operation not supported.\n");
+ }
+ cpg->freqcr = val;
+ update_divrate(cpg);
+ break;
+ case A_STBCR:
+ case A_STBCR2:
+ if (size != 1) {
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid access size.\n", addr);
+ return;
+ }
+ reg = extract32(addr, 4, 1); /* STBCR -> 0x04 / STBCR2 -> 0x10 */
+ old_stbcr = cpg->stbcr[reg];
+ old_stbcr ^= val;
+ cpg->stbcr[reg] = val;
+ update_stbcr(cpg, reg, old_stbcr);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid address.\n", addr);
+ }
+}
+
+static uint64_t stp_read(void *opaque, hwaddr addr, unsigned size)
+{
+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
+
+ switch (addr) {
+ case A_CLKSTP00:
+ return cpg->clkstp00;
+ case A_CLKSTPCLR00:
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "sh7751-cpg: CLKSTPCLR00 is write only.\n");
+ return UINT64_MAX;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid address.\n", addr);
+ return UINT64_MAX;
+ }
+}
+
+static void stp_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
+{
+ SH7751CPGBaseState *cpg = SH7751CPGBase(opaque);
+
+ val &= 0x7;
+ switch (addr) {
+ case A_CLKSTP00:
+ cpg->clkstp00 |= val;
+ update_stbcr(cpg, 2, val);
+ break;
+ case A_CLKSTPCLR00:
+ cpg->clkstp00 &= ~val;
+ update_stbcr(cpg, 2, val);
+ break;
+ default:
+ qemu_log_mask(LOG_GUEST_ERROR, "sh7751-cpg: Register 0x%"
+ HWADDR_PRIX " Invalid address.\n", addr);
+ }
+}
+
+static int sh7751_pll1mul(int mode, uint16_t freqcr)
+{
+ int div1;
+ int pll1;
+ switch (mode) {
+ case 3:
+ case 5:
+ case 6:
+ div1 = 2;
+ break;
+ default:
+ div1 = 1;
+ }
+ if (FIELD_EX16(freqcr, FREQCR, PLL1EN)) {
+ pll1 = 6;
+ } else {
+ pll1 = 1;
+ }
+ return pll1 / div1;
+}
+
+static int sh7751r_pll1mul(int mode, uint16_t freqcr)
+{
+ int pll1;
+ switch (mode) {
+ case 0:
+ case 1:
+ case 3:
+ case 5:
+ pll1 = 12;
+ break;
+ case 2:
+ case 4:
+ case 6:
+ pll1 = 6;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ if (!FIELD_EX16(freqcr, FREQCR, PLL1EN)) {
+ pll1 = 1;
+ }
+ return pll1;
+}
+
+static const MemoryRegionOps cpg_ops = {
+ .write = cpg_write,
+ .read = cpg_read,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 1,
+ .max_access_size = 4,
+ },
+};
+
+static const MemoryRegionOps stp_ops = {
+ .write = stp_write,
+ .read = stp_read,
+ .endianness = DEVICE_NATIVE_ENDIAN,
+ .impl = {
+ .min_access_size = 4,
+ .max_access_size = 4,
+ },
+};
+
+static const ClockPortInitArray sh7751_cpg_clocks = {
+ QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_ick),
+ QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_bck),
+ QDEV_CLOCK_OUT(SH7751CPGBaseState, clk_pck),
+ QDEV_CLOCK_END
+};
+
+static void sh7751cpg_realize(DeviceState *dev, Error **errp)
+{
+ SH7751CPGBaseState *cpg = SH7751CPGBase(dev);
+ SH7751CPGBaseClass *k = SH7751CPG_GET_CLASS(cpg);
+
+ if (cpg->xtal_freq_hz == 0) {
+ error_setg(errp, "\"xtal-frequency-hz\" property must be provided.");
+ return;
+ }
+ /* XTAL range: 1-34 MHz */
+ if (cpg->xtal_freq_hz < SH7751_XTAL_MIN_HZ ||
+ cpg->xtal_freq_hz > SH7751_XTAL_MAX_HZ) {
+ error_setg(errp, "\"xtal-frequency-hz\" property in incorrect range.");
+ return;
+ }
+ /* Clock mode: 0 - 6 */
+ if (cpg->clock_mode > 6) {
+ error_setg(errp, "\"clock-mode\" property in incorrect range.");
+ return;
+ }
+
+ cpg->freqcr = k->initfreqcr[cpg->clock_mode];
+ update_divrate(cpg);
+}
+
+static void sh7751_cpg_init(Object *obj)
+{
+ SH7751CPGBaseState *cpg = SH7751CPGBase(obj);
+ const dev_clock_t *p = dev_clock_list;
+ qdev_init_clocks(DEVICE(obj), sh7751_cpg_clocks);
+ /* connect parent clock */
+ while (p->name) {
+ cpg->dev_clocks[p->devnum] = qdev_init_clock_out(DEVICE(obj),
+ p->name);
+ p++;
+ }
+
+ memory_region_init_io(&cpg->memory[0], OBJECT(cpg), &cpg_ops,
+ cpg, "sh7751-cpg", 0x14);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[0]);
+ memory_region_init_alias(&cpg->memory[1], NULL,
+ "sh7751-cpg-a4", &cpg->memory[0], 0, 0x14);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[1]);
+ memory_region_init_alias(&cpg->memory[2], NULL,
+ "sh7751-cpg-p7", &cpg->memory[0], 0, 0x14);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[2]);
+ memory_region_init_io(&cpg->memory[3], OBJECT(cpg), &stp_ops,
+ cpg, "sh7751-stp", 0x10);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[3]);
+ memory_region_init_alias(&cpg->memory[4], NULL,
+ "sh7751-stp-a4", &cpg->memory[3], 0, 0x10);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[4]);
+ memory_region_init_alias(&cpg->memory[5], NULL,
+ "sh7751-stp-p7", &cpg->memory[3], 0, 0x10u);
+ sysbus_init_mmio(SYS_BUS_DEVICE(obj), &cpg->memory[5]);
+}
+
+static Property sh7751_cpg_properties[] = {
+ DEFINE_PROP_UINT32("xtal-frequency-hz",
+ SH7751CPGBaseState, xtal_freq_hz, 0),
+ DEFINE_PROP_UINT32("clock-mode",
+ SH7751CPGBaseState, clock_mode, 0),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
+static void sh7751cpg_base_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+
+ device_class_set_props(dc, sh7751_cpg_properties);
+}
+
+static void sh7751cpg_class_init(ObjectClass *klass, void *data)
+{
+ SH7751CPGBaseClass *base = SH7751CPGBaseClass(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ static uint16_t initfreqcr[] = {0x0e1a, 0x0e23, 0x0e13, 0x0e13,
+ 0x0e0a, 0x0e0a, 0x0808};
+
+ base->pll1mul = sh7751_pll1mul;
+ base->initfreqcr = initfreqcr;
+ dc->realize = sh7751cpg_realize;
+}
+
+static void sh7751rcpg_class_init(ObjectClass *klass, void *data)
+{
+ SH7751CPGBaseClass *base = SH7751CPGBaseClass(klass);
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ static uint16_t initfreqcr[] = {0x0e1a, 0x0e2c, 0x0e13, 0x0e13,
+ 0x0e0a, 0x0e0a, 0x0808};
+
+ base->pll1mul = sh7751r_pll1mul;
+ base->initfreqcr = initfreqcr;
+ dc->realize = sh7751cpg_realize;
+}
+
+static const TypeInfo sh7751cpg_info[] = {
+ {
+ .name = TYPE_SH7751_CPG_BASE,
+ .parent = TYPE_SYS_BUS_DEVICE,
+ .instance_size = sizeof(SH7751CPGBaseState),
+ .class_init = sh7751cpg_base_class_init,
+ .class_size = sizeof(SH7751CPGBaseClass),
+ .abstract = true,
+ },
+ {
+ .name = TYPE_SH7751_CPG,
+ .parent = TYPE_SH7751_CPG_BASE,
+ .instance_size = sizeof(SH7751CPGState),
+ .instance_init = sh7751_cpg_init,
+ .class_init = sh7751cpg_class_init,
+ .class_size = sizeof(SH7751CPGClass),
+ },
+ {
+ .name = TYPE_SH7751R_CPG,
+ .parent = TYPE_SH7751_CPG_BASE,
+ .instance_size = sizeof(SH7751RCPGState),
+ .instance_init = sh7751_cpg_init,
+ .class_init = sh7751rcpg_class_init,
+ .class_size = sizeof(SH7751RCPGClass),
+ },
+};
+
+DEFINE_TYPES(sh7751cpg_info)
diff --git a/hw/sh4/meson.build b/hw/sh4/meson.build
index 424d5674de..7ed8246152 100644
--- a/hw/sh4/meson.build
+++ b/hw/sh4/meson.build
@@ -2,6 +2,7 @@ sh4_ss = ss.source_set()
sh4_ss.add(files(
'sh7750.c',
'sh7750_regnames.c',
+ 'sh7751-cpg.c',
))
sh4_ss.add(when: 'CONFIG_R2D', if_true: files('r2d.c'))
sh4_ss.add(when: 'CONFIG_SHIX', if_true: files('shix.c'))
--
2.20.1
next prev parent reply other threads:[~2021-05-27 5:28 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-05-27 5:21 [PATCH 00/11] Unified peripheral emulation for Renesas chips Yoshinori Sato
2021-05-27 5:21 ` [PATCH 01/11] hw/char: Renesas SCI module Yoshinori Sato
2021-06-04 9:09 ` Peter Maydell
2021-06-06 14:31 ` Yoshinori Sato
2021-06-06 14:36 ` Yoshinori Sato
2021-05-27 5:21 ` [PATCH 02/11] hw/char: remove sh_serial Yoshinori Sato
2021-06-04 10:08 ` Peter Maydell
2021-06-06 14:33 ` Yoshinori Sato
2021-06-06 14:33 ` Yoshinori Sato
2021-06-06 14:37 ` Yoshinori Sato
2021-05-27 5:21 ` [PATCH 03/11] hw/timer: Renesas TMU/CMT module Yoshinori Sato
2021-05-27 5:21 ` [PATCH 04/11] hw/timer: Remove sh_timer Yoshinori Sato
2021-05-27 5:21 ` [PATCH 05/11] hw/timer: Remove renesas_cmt Yoshinori Sato
2021-05-27 5:21 ` [PATCH 06/11] hw/rx: Add RX62N Clock generator Yoshinori Sato
2021-05-27 5:21 ` [PATCH 07/11] hw/timer: Renesas 8bit timer Yoshinori Sato
2021-06-04 10:12 ` Peter Maydell
2021-05-27 5:21 ` [PATCH 08/11] hw/rx: rx62n use new hw modules Yoshinori Sato
2021-05-27 5:21 ` Yoshinori Sato [this message]
2021-05-27 5:21 ` [PATCH 10/11] hw/sh4: sh7750 " Yoshinori Sato
2021-05-27 5:21 ` [PATCH 11/11] hw/rx: rx-gdbsim Add bootstrup for linux Yoshinori Sato
2021-05-27 5:33 ` [PATCH 00/11] Unified peripheral emulation for Renesas chips no-reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210527052122.97103-10-ysato@users.sourceforge.jp \
--to=ysato@users.sourceforge.jp \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.