1 | /* |
2 | * QEMU Crystal CS4231 audio chip emulation |
3 | * |
4 | * Copyright (c) 2006 Fabrice Bellard |
5 | * |
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | * of this software and associated documentation files (the "Software"), to deal |
8 | * in the Software without restriction, including without limitation the rights |
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
10 | * copies of the Software, and to permit persons to whom the Software is |
11 | * furnished to do so, subject to the following conditions: |
12 | * |
13 | * The above copyright notice and this permission notice shall be included in |
14 | * all copies or substantial portions of the Software. |
15 | * |
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
19 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
22 | * THE SOFTWARE. |
23 | */ |
24 | |
25 | #include "qemu/osdep.h" |
26 | #include "hw/sysbus.h" |
27 | #include "migration/vmstate.h" |
28 | #include "qemu/module.h" |
29 | #include "trace.h" |
30 | |
31 | /* |
32 | * In addition to Crystal CS4231 there is a DMA controller on Sparc. |
33 | */ |
34 | #define CS_SIZE 0x40 |
35 | #define CS_REGS 16 |
36 | #define CS_DREGS 32 |
37 | #define CS_MAXDREG (CS_DREGS - 1) |
38 | |
39 | #define TYPE_CS4231 "SUNW,CS4231" |
40 | #define CS4231(obj) \ |
41 | OBJECT_CHECK(CSState, (obj), TYPE_CS4231) |
42 | |
43 | typedef struct CSState { |
44 | SysBusDevice parent_obj; |
45 | |
46 | MemoryRegion iomem; |
47 | qemu_irq irq; |
48 | uint32_t regs[CS_REGS]; |
49 | uint8_t dregs[CS_DREGS]; |
50 | } CSState; |
51 | |
52 | #define CS_RAP(s) ((s)->regs[0] & CS_MAXDREG) |
53 | #define CS_VER 0xa0 |
54 | #define CS_CDC_VER 0x8a |
55 | |
56 | static void cs_reset(DeviceState *d) |
57 | { |
58 | CSState *s = CS4231(d); |
59 | |
60 | memset(s->regs, 0, CS_REGS * 4); |
61 | memset(s->dregs, 0, CS_DREGS); |
62 | s->dregs[12] = CS_CDC_VER; |
63 | s->dregs[25] = CS_VER; |
64 | } |
65 | |
66 | static uint64_t cs_mem_read(void *opaque, hwaddr addr, |
67 | unsigned size) |
68 | { |
69 | CSState *s = opaque; |
70 | uint32_t saddr, ret; |
71 | |
72 | saddr = addr >> 2; |
73 | switch (saddr) { |
74 | case 1: |
75 | switch (CS_RAP(s)) { |
76 | case 3: // Write only |
77 | ret = 0; |
78 | break; |
79 | default: |
80 | ret = s->dregs[CS_RAP(s)]; |
81 | break; |
82 | } |
83 | trace_cs4231_mem_readl_dreg(CS_RAP(s), ret); |
84 | break; |
85 | default: |
86 | ret = s->regs[saddr]; |
87 | trace_cs4231_mem_readl_reg(saddr, ret); |
88 | break; |
89 | } |
90 | return ret; |
91 | } |
92 | |
93 | static void cs_mem_write(void *opaque, hwaddr addr, |
94 | uint64_t val, unsigned size) |
95 | { |
96 | CSState *s = opaque; |
97 | uint32_t saddr; |
98 | |
99 | saddr = addr >> 2; |
100 | trace_cs4231_mem_writel_reg(saddr, s->regs[saddr], val); |
101 | switch (saddr) { |
102 | case 1: |
103 | trace_cs4231_mem_writel_dreg(CS_RAP(s), s->dregs[CS_RAP(s)], val); |
104 | switch(CS_RAP(s)) { |
105 | case 11: |
106 | case 25: // Read only |
107 | break; |
108 | case 12: |
109 | val &= 0x40; |
110 | val |= CS_CDC_VER; // Codec version |
111 | s->dregs[CS_RAP(s)] = val; |
112 | break; |
113 | default: |
114 | s->dregs[CS_RAP(s)] = val; |
115 | break; |
116 | } |
117 | break; |
118 | case 2: // Read only |
119 | break; |
120 | case 4: |
121 | if (val & 1) { |
122 | cs_reset(DEVICE(s)); |
123 | } |
124 | val &= 0x7f; |
125 | s->regs[saddr] = val; |
126 | break; |
127 | default: |
128 | s->regs[saddr] = val; |
129 | break; |
130 | } |
131 | } |
132 | |
133 | static const MemoryRegionOps cs_mem_ops = { |
134 | .read = cs_mem_read, |
135 | .write = cs_mem_write, |
136 | .endianness = DEVICE_NATIVE_ENDIAN, |
137 | }; |
138 | |
139 | static const VMStateDescription vmstate_cs4231 = { |
140 | .name ="cs4231" , |
141 | .version_id = 1, |
142 | .minimum_version_id = 1, |
143 | .fields = (VMStateField[]) { |
144 | VMSTATE_UINT32_ARRAY(regs, CSState, CS_REGS), |
145 | VMSTATE_UINT8_ARRAY(dregs, CSState, CS_DREGS), |
146 | VMSTATE_END_OF_LIST() |
147 | } |
148 | }; |
149 | |
150 | static void cs4231_init(Object *obj) |
151 | { |
152 | CSState *s = CS4231(obj); |
153 | SysBusDevice *dev = SYS_BUS_DEVICE(obj); |
154 | |
155 | memory_region_init_io(&s->iomem, obj, &cs_mem_ops, s, "cs4321" , |
156 | CS_SIZE); |
157 | sysbus_init_mmio(dev, &s->iomem); |
158 | sysbus_init_irq(dev, &s->irq); |
159 | } |
160 | |
161 | static Property cs4231_properties[] = { |
162 | {.name = NULL}, |
163 | }; |
164 | |
165 | static void cs4231_class_init(ObjectClass *klass, void *data) |
166 | { |
167 | DeviceClass *dc = DEVICE_CLASS(klass); |
168 | |
169 | dc->reset = cs_reset; |
170 | dc->vmsd = &vmstate_cs4231; |
171 | dc->props = cs4231_properties; |
172 | } |
173 | |
174 | static const TypeInfo cs4231_info = { |
175 | .name = TYPE_CS4231, |
176 | .parent = TYPE_SYS_BUS_DEVICE, |
177 | .instance_size = sizeof(CSState), |
178 | .instance_init = cs4231_init, |
179 | .class_init = cs4231_class_init, |
180 | }; |
181 | |
182 | static void cs4231_register_types(void) |
183 | { |
184 | type_register_static(&cs4231_info); |
185 | } |
186 | |
187 | type_init(cs4231_register_types) |
188 | |