[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 4/8] hw/char/escc2: Add clock generation
From: |
Jasper Lowell |
Subject: |
[PATCH 4/8] hw/char/escc2: Add clock generation |
Date: |
Wed, 17 Jun 2020 18:23:58 +1000 |
Each channel on the controller has dedicated pins for providing receive
and transmit clock sources, a baud rate generator, and a DPLL.
Additionally, the controller has two pins, XTAL1 and XTAL2, that can be
used with a crystal and oscillator for providing a clock source.
Alternatively, XTAL1 can simply be used as a clock source. These
components are used individually or together according to register
configurations for generating the final receive and transmit clocks.
Signed-off-by: Jasper Lowell <jasper.lowell@bt.com>
---
hw/char/escc2.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 177 insertions(+), 2 deletions(-)
diff --git a/hw/char/escc2.c b/hw/char/escc2.c
index e16049ce4d..059e033089 100644
--- a/hw/char/escc2.c
+++ b/hw/char/escc2.c
@@ -106,9 +106,31 @@
/* CCR1. */
#define REGISTER_CCR1_OFFSET 0x2d
+#define REGISTER_CCR1_ODS 0x10
+#define REGISTER_CCR1_BCR 0x8
+#define REGISTER_CCR1_CM2 0x4
+#define REGISTER_CCR1_CM1 0x2
+#define REGISTER_CCR1_CM0 0x1
+
+#define REGISTER_CCR1_CM_MASK \
+ (REGISTER_CCR1_CM2 | REGISTER_CCR1_CM1 | REGISTER_CCR1_CM0)
/* CCR2. */
#define REGISTER_CCR2_OFFSET 0x2e
+#define REGISTER_CCR2_SOC1 0x80
+#define REGISTER_CCR2_BR9 0x80
+#define REGISTER_CCR2_SOC0 0x40
+#define REGISTER_CCR2_BR8 0x40
+#define REGISTER_CCR2_BDF 0x20
+#define REGISTER_CCR2_XCS0 0x20
+#define REGISTER_CCR2_SSEL 0x10
+#define REGISTER_CCR2_RCS0 0x10
+#define REGISTER_CCR2_TOE 0x8
+#define REGISTER_CCR2_RWX 0x4
+#define REGISTER_CCR2_DIV 0x1
+
+#define REGISTER_CCR2_BR_MASK \
+ (REGISTER_CCR2_BR8 | REGISTER_CCR2_BR9)
/* CCR3. */
#define REGISTER_CCR3_OFFSET 0x2f
@@ -131,6 +153,9 @@
/* BGR. */
#define REGISTER_BGR_OFFSET 0x34
+#define REGISTER_BGR_EN_MASK 0x3f
+#define REGISTER_BGR_EM_MASK 0xc0
+
/* TIC. */
#define REGISTER_TIC_OFFSET 0x35
@@ -194,6 +219,10 @@
/* CCR4. */
#define REGISTER_CCR4_OFFSET 0x3f
+#define REGISTER_CCR4_MCK4 0x80
+#define REGISTER_CCR4_EBRG 0x40
+#define REGISTER_CCR4_TST1 0x20
+#define REGISTER_CCR4_ICD 0x10
enum {
REGISTER_STAR = 0,
@@ -244,6 +273,14 @@ typedef struct ESCC2State ESCC2State;
typedef struct ESCC2ChannelState {
ESCC2State *controller;
+ /*
+ * Each channel has dedicated pins for providing receive and transmit clock
+ * sources. These dedicated pins are a subset of a larger set of selectable
+ * clock sources.
+ */
+ unsigned int rxclock;
+ unsigned int txclock;
+
CharBackend chardev;
/*
@@ -275,6 +312,14 @@ enum {
struct ESCC2State {
DeviceState parent;
+ /*
+ * The controller has two pins: XTAL1 and XTAL2. These pins can be used
+ * together with a crystal and oscillator to provide a clock source.
+ * Alternatively, XTAL1 can provide an externally generated clock source.
+ * These configurations are mutually exclusive.
+ */
+ unsigned int xtal;
+
MemoryRegion io;
qemu_irq irq;
ESCC2ChannelState channel[CHANNEL_COUNT];
@@ -376,9 +421,130 @@ static void escc2_channel_irq_event(ESCC2ChannelState
*channel,
}
}
+static float escc2_channel_baud_rate_generate(ESCC2ChannelState *channel,
+ unsigned int clock)
+{
+ /*
+ * Each channel has an independent baud rate generator. This baud rate
+ * generator can act as a clock source for receiving, transmitting, and/or
+ * for the DPLL.
+ */
+ int k, n, m;
+ uint8_t ccr2 = REGISTER_READ(channel, REGISTER_CCR2);
+ uint8_t bgr = REGISTER_READ(channel, REGISTER_BGR);
+
+ if (REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_BDF) {
+ /* The baud rate division factor k relies on BGR. */
+ if (REGISTER_READ(channel, REGISTER_CCR4) & REGISTER_CCR4_EBRG) {
+ /* Enhanced mode. */
+ n = bgr & REGISTER_BGR_EN_MASK;
+ m = ((ccr2 & REGISTER_CCR2_BR_MASK) >> 6)
+ | ((bgr & REGISTER_BGR_EM_MASK) >> 6);
+ k = (n + 1) * (2 * m);
+ } else {
+ /* Standard mode. */
+ n = ((ccr2 & REGISTER_CCR2_BR_MASK) << 2) | bgr;
+ k = (n + 1) * 2;
+ }
+ } else {
+ k = 1;
+ }
+
+ return (float) clock / (16 * k);
+}
+
+static void escc2_channel_io_speed(ESCC2ChannelState *channel, float *input,
+ float *output)
+{
+ /*
+ * The receive and transmit speed can be configured to leverage dedicated
+ * receive and transmit clock source pins, the channel independent baud
rate
+ * generator, the DPLL for handling clock synchronisation, the onboard
+ * oscillator, and a designated master clock. Different combinations of
+ * these are selected by specifying the clock mode and submode.
+ *
+ * Note: The DPLL, to function correctly, requires a clock source with a
+ * frequency 16 times the nominal bit rate so that the DPLL can synchronise
+ * the clock with the input stream. When the DPLL is used, the frequency
+ * must be divided by 16.
+ */
+ unsigned int mode = REGISTER_READ(channel, REGISTER_CCR1)
+ & REGISTER_CCR1_CM_MASK;
+ unsigned int submode = REGISTER_READ(channel, REGISTER_CCR2)
+ & REGISTER_CCR2_SSEL;
+
+ /* Clock modes are numbered 0 through 7. */
+ switch (mode) {
+ case 0:
+ *input = channel->rxclock;
+ if (!submode) {
+ /* 0a. */
+ *output = channel->txclock;
+ } else {
+ /* 0b. */
+ *output = escc2_channel_baud_rate_generate(channel,
+ channel->controller->xtal);
+ }
+ break;
+ case 1:
+ *input = channel->rxclock;
+ *output = *input;
+ break;
+ case 2:
+ *input = escc2_channel_baud_rate_generate(channel, channel->rxclock)
+ / 16;
+ if (!(REGISTER_READ(channel, REGISTER_CCR2)
+ & REGISTER_CCR2_SSEL)) {
+ /* 2a. */
+ *output = channel->txclock;
+ } else {
+ /* 2b. */
+ *output = *input;
+ }
+ break;
+ case 3:
+ *input = escc2_channel_baud_rate_generate(channel, channel->rxclock);
+ if (!(REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_SSEL)) {
+ /* 3a. */
+ *input /= 16;
+ }
+ *output = *input;
+ break;
+ case 4:
+ *input = channel->controller->xtal;
+ *output = *input;
+ case 5:
+ *input = channel->rxclock;
+ *output = *input;
+ case 6:
+ *input = escc2_channel_baud_rate_generate(channel,
+ channel->controller->xtal) / 16;
+ if (!(REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_SSEL)) {
+ /* 6a. */
+ *output = channel->txclock;
+ } else {
+ /* 6b. */
+ *output = *input;
+ }
+ break;
+ case 7:
+ *input = escc2_channel_baud_rate_generate(channel,
+ channel->controller->xtal);
+ if (!(REGISTER_READ(channel, REGISTER_CCR2) & REGISTER_CCR2_SSEL)) {
+ /* 7a. */
+ *input /= 16;
+ }
+ *output = *input;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
static void escc2_channel_parameters_update(ESCC2ChannelState *channel)
{
uint8_t dafo;
+ float ispeed, ospeed;
QEMUSerialSetParams ssp;
if (!qemu_chr_fe_backend_connected(&channel->chardev)) {
@@ -434,8 +600,12 @@ static void
escc2_channel_parameters_update(ESCC2ChannelState *channel)
ssp.stop_bits = 1;
}
- /* XXX */
- ssp.speed = 0;
+ /*
+ * XXX: QEMU doesn't support configurations with different input/output
+ * speeds yet so the input speed is used for both.
+ */
+ escc2_channel_io_speed(channel, &ispeed, &ospeed);
+ ssp.speed = ispeed;
qemu_chr_fe_ioctl(&channel->chardev, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
}
@@ -852,6 +1022,11 @@ static void escc2_isa_instance_init(Object *o)
static Property escc2_properties[] = {
DEFINE_PROP_CHR("chardevA", ESCC2State, channel[CHANNEL_A].chardev),
DEFINE_PROP_CHR("chardevB", ESCC2State, channel[CHANNEL_B].chardev),
+ DEFINE_PROP_UINT32("xtal", ESCC2State, xtal, 0),
+ DEFINE_PROP_UINT32("rxclockA", ESCC2State, channel[CHANNEL_A].rxclock, 0),
+ DEFINE_PROP_UINT32("txclockA", ESCC2State, channel[CHANNEL_A].txclock, 0),
+ DEFINE_PROP_UINT32("rxclockB", ESCC2State, channel[CHANNEL_B].rxclock, 0),
+ DEFINE_PROP_UINT32("txclockB", ESCC2State, channel[CHANNEL_B].txclock, 0),
DEFINE_PROP_END_OF_LIST()
};
--
2.26.2
- [PATCH 0/8] ESCC2, Jasper Lowell, 2020/06/17
- [PATCH 1/8] hw/char/escc2: Add device, Jasper Lowell, 2020/06/17
- [PATCH 2/8] hw/char/escc2: Handle interrupt generation, Jasper Lowell, 2020/06/17
- [PATCH 3/8] hw/char/escc2: Add character device backend, Jasper Lowell, 2020/06/17
- [PATCH 5/8] hw/char/escc2: Add Receiver Reset (RRES) command, Jasper Lowell, 2020/06/17
- [PATCH 4/8] hw/char/escc2: Add clock generation,
Jasper Lowell <=
- [PATCH 6/8] hw/char/escc2: Add RFRD command, Jasper Lowell, 2020/06/17
- [PATCH 7/8] hw/char/escc2: Add Transmit Frame (XF) command, Jasper Lowell, 2020/06/17
- [PATCH 8/8] hw/char/escc2: Add XRES command, Jasper Lowell, 2020/06/17
- Re: [PATCH 0/8] ESCC2, no-reply, 2020/06/17
- Re: [PATCH 0/8] ESCC2, Philippe Mathieu-Daudé, 2020/06/17
- Re: [PATCH 0/8] ESCC2, Artyom Tarasenko, 2020/06/17