3 * Samsung S3C24XX Serial block
5 * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
7 * Copyright 2010, 2013, 2020 Stefan Weil
9 * This file is under the terms of the GNU General Public License Version 2.
12 #include "qemu/osdep.h"
13 #include "chardev/char-fe.h" /* qemu_chr_fe_write */
15 #include "exec/address-spaces.h" /* get_system_memory */
17 #include "hw/irq.h" /* qemu_set_irq */
18 #include "sysemu/sysemu.h"
23 # define DEBUG_S3C24XX
26 #if defined(DEBUG_S3C24XX)
27 # define logout(fmt, ...) \
28 fprintf(stderr, "S3C24xx\t%-24s" fmt, __func__, ##__VA_ARGS__)
30 # define logout(fmt, ...) (void)0
33 /* S3C24XX serial port registers */
35 /* Line control RW WORD */
36 #define S3C_SERIAL_ULCON 0x00
37 /* General control RW WORD */
38 #define S3C_SERIAL_UCON 0x04
39 /* Fifo control RW WORD */
40 #define S3C_SERIAL_UFCON 0x08
41 /* Modem control RW WORD */
42 #define S3C_SERIAL_UMCON 0x0C
43 /* TX/RX Status RO WORD */
44 #define S3C_SERIAL_UTRSTAT 0x10
45 /* Receive Error Status RO WORD */
46 #define S3C_SERIAL_UERSTAT 0x14
47 /* FiFo Status RO WORD */
48 #define S3C_SERIAL_UFSTAT 0x18
49 /* Modem Status RO WORD */
50 #define S3C_SERIAL_UMSTAT 0x1C
51 /* TX buffer WR BYTE */
52 #define S3C_SERIAL_UTXH 0x20
53 /* RX buffer RO BYTE */
54 #define S3C_SERIAL_URXH 0x24
55 /* BAUD Divisor RW WORD */
56 #define S3C_SERIAL_UBRDIV 0x28
58 /* S3C24XX serial port state */
59 typedef struct s3c24xx_serial_dev_s
{
61 uint32_t ulcon
, ucon
, ufcon
, umcon
, ubrdiv
;
62 unsigned char rx_byte
;
63 /* Byte is available to be read */
64 unsigned int rx_available
: 1;
72 static void s3c24xx_serial_write(void *opaque
, hwaddr addr
,
73 uint64_t value
, unsigned size
)
75 s3c24xx_serial_dev
*s
= opaque
;
76 int reg
= addr
& 0x3f;
78 logout("0x" TARGET_FMT_plx
" 0x%08x\n", addr
, value
);
81 case S3C_SERIAL_ULCON
:
87 if( s
->ucon
& 1<<9 ) {
88 qemu_set_irq(s
->tx_level
, 1);
90 qemu_set_irq(s
->tx_level
, 0);
92 if( !(s
->ucon
& 1<<8) ) {
93 qemu_set_irq(s
->rx_level
, 0);
97 case S3C_SERIAL_UFCON
:
98 s
->ufcon
= (value
& ~6);
101 case S3C_SERIAL_UMCON
:
105 case S3C_SERIAL_UTRSTAT
:
108 case S3C_SERIAL_UERSTAT
:
111 case S3C_SERIAL_UFSTAT
:
114 case S3C_SERIAL_UMSTAT
:
117 case S3C_SERIAL_UTXH
: {
118 unsigned char ch
= value
& 0xff;
119 if ((s
->ucon
& 1 << 5) == 0) {
120 qemu_chr_fe_write(&s
->chr
, &ch
, 1);
124 if( s
->ucon
& 1<<8 ) {
125 qemu_set_irq(s
->rx_level
, 1);
127 qemu_set_irq(s
->rx_irq
, 1);
130 if (s
->ucon
& 1<<9) {
131 qemu_set_irq(s
->tx_level
, 1);
133 qemu_set_irq(s
->tx_irq
, 1);
138 case S3C_SERIAL_URXH
:
141 case S3C_SERIAL_UBRDIV
:
150 static uint64_t s3c24xx_serial_read(void *opaque
, hwaddr addr
,
153 s3c24xx_serial_dev
*s
= opaque
;
154 int reg
= addr
& 0x3f;
156 logout("0x" TARGET_FMT_plx
"\n", addr
);
159 case S3C_SERIAL_ULCON
:
162 case S3C_SERIAL_UCON
:
165 case S3C_SERIAL_UFCON
:
166 return s
->ufcon
& ~0x8; /* bit 3 is reserved, must be zero */
168 case S3C_SERIAL_UMCON
:
169 return s
->umcon
& 0x11; /* Rest are reserved, must be zero */
171 case S3C_SERIAL_UTRSTAT
:
172 return 6 | s
->rx_available
; /* TX always clear, RX when available */
174 case S3C_SERIAL_UERSTAT
:
175 return 0; /* Later, break detect comes in here */
177 case S3C_SERIAL_UFSTAT
:
178 return s
->rx_available
; /* TXFIFO, always empty, RXFIFO 0 or 1 bytes */
180 case S3C_SERIAL_UMSTAT
:
183 case S3C_SERIAL_UTXH
:
186 case S3C_SERIAL_URXH
:
188 if (s
->ucon
& 1<<8) {
189 qemu_set_irq(s
->rx_level
, 0);
193 case S3C_SERIAL_UBRDIV
:
201 static const MemoryRegionOps s3c24xx_serial_ops
= {
202 .read
= s3c24xx_serial_read
,
203 .write
= s3c24xx_serial_write
,
204 .endianness
= DEVICE_NATIVE_ENDIAN
,
206 .min_access_size
= 1,
211 static void s3c24xx_serial_event(void *opaque
, int event
)
216 s3c24xx_serial_can_receive(void *opaque
)
218 s3c24xx_serial_dev
*s
= opaque
;
220 /* If there's no byte to be read, we can receive a new one */
221 return !s
->rx_available
;
225 s3c24xx_serial_receive(void *opaque
, const uint8_t *buf
, int size
)
227 s3c24xx_serial_dev
*s
= opaque
;
230 if ( s
->ucon
& 1 << 8 ) {
231 qemu_set_irq(s
->rx_level
, 1);
233 /* Is there something we can do here to ensure it's just a pulse ? */
234 qemu_set_irq(s
->rx_irq
, 1);
238 /* Create a S3C serial port, the port implementation is common to all
239 * current s3c devices only differing in the I/O base address and number of
242 struct s3c24xx_serial_dev_s
*
243 s3c24xx_serial_init(S3CState
*soc
,
248 /* Initialise a serial port at the given port address */
249 s3c24xx_serial_dev
*s
= g_new0(s3c24xx_serial_dev
, 1);
251 /* initialise serial port context */
252 s
->rx_irq
= s3c24xx_get_irq(soc
->irq
, irqn
);
253 s
->rx_level
= s3c24xx_get_irq(soc
->irq
, irqn
+ 64);
255 s
->tx_irq
= s3c24xx_get_irq(soc
->irq
, irqn
+ 1);
256 s
->tx_level
= s3c24xx_get_irq(soc
->irq
, irqn
+ 1 + 64);
258 /* Register the MMIO region. */
259 memory_region_init_io(&s
->mmio
, OBJECT(s
), &s3c24xx_serial_ops
, s
,
260 "s3c24xx.serial", 44);
261 memory_region_add_subregion(get_system_memory(), base_addr
, &s
->mmio
);
263 qemu_chr_fe_set_handlers(&s
->chr
,
264 s3c24xx_serial_can_receive
,
265 s3c24xx_serial_receive
,
266 s3c24xx_serial_event
,
267 NULL
, s
, NULL
, true);