]>
Commit | Line | Data |
---|---|---|
7880febd PB |
1 | /* |
2 | * Toshiba TC6393XB I/O Controller. | |
3 | * Found in Sharp Zaurus SL-6000 (tosa) or some | |
4 | * Toshiba e-Series PDAs. | |
5 | * | |
6 | * Most features are currently unsupported!!! | |
7 | * | |
8 | * This code is licensed under the GNU GPL v2. | |
9 | */ | |
88d2c950 AZ |
10 | #include "hw.h" |
11 | #include "pxa.h" | |
12 | #include "devices.h" | |
13 | ||
14 | #define TC6393XB_GPIOS 16 | |
15 | ||
16 | #define SCR_REVID 0x08 /* b Revision ID */ | |
17 | #define SCR_ISR 0x50 /* b Interrupt Status */ | |
18 | #define SCR_IMR 0x52 /* b Interrupt Mask */ | |
19 | #define SCR_IRR 0x54 /* b Interrupt Routing */ | |
20 | #define SCR_GPER 0x60 /* w GP Enable */ | |
21 | #define SCR_GPI_SR(i) (0x64 + (i)) /* b3 GPI Status */ | |
22 | #define SCR_GPI_IMR(i) (0x68 + (i)) /* b3 GPI INT Mask */ | |
23 | #define SCR_GPI_EDER(i) (0x6c + (i)) /* b3 GPI Edge Detect Enable */ | |
24 | #define SCR_GPI_LIR(i) (0x70 + (i)) /* b3 GPI Level Invert */ | |
25 | #define SCR_GPO_DSR(i) (0x78 + (i)) /* b3 GPO Data Set */ | |
26 | #define SCR_GPO_DOECR(i) (0x7c + (i)) /* b3 GPO Data OE Control */ | |
27 | #define SCR_GP_IARCR(i) (0x80 + (i)) /* b3 GP Internal Active Register Control */ | |
28 | #define SCR_GP_IARLCR(i) (0x84 + (i)) /* b3 GP INTERNAL Active Register Level Control */ | |
29 | #define SCR_GPI_BCR(i) (0x88 + (i)) /* b3 GPI Buffer Control */ | |
30 | #define SCR_GPA_IARCR 0x8c /* w GPa Internal Active Register Control */ | |
31 | #define SCR_GPA_IARLCR 0x90 /* w GPa Internal Active Register Level Control */ | |
32 | #define SCR_GPA_BCR 0x94 /* w GPa Buffer Control */ | |
33 | #define SCR_CCR 0x98 /* w Clock Control */ | |
34 | #define SCR_PLL2CR 0x9a /* w PLL2 Control */ | |
35 | #define SCR_PLL1CR 0x9c /* l PLL1 Control */ | |
36 | #define SCR_DIARCR 0xa0 /* b Device Internal Active Register Control */ | |
37 | #define SCR_DBOCR 0xa1 /* b Device Buffer Off Control */ | |
38 | #define SCR_FER 0xe0 /* b Function Enable */ | |
39 | #define SCR_MCR 0xe4 /* w Mode Control */ | |
40 | #define SCR_CONFIG 0xfc /* b Configuration Control */ | |
41 | #define SCR_DEBUG 0xff /* b Debug */ | |
42 | ||
43 | struct tc6393xb_s { | |
44 | target_phys_addr_t target_base; | |
45 | struct { | |
46 | uint8_t ISR; | |
47 | uint8_t IMR; | |
48 | uint8_t IRR; | |
49 | uint16_t GPER; | |
50 | uint8_t GPI_SR[3]; | |
51 | uint8_t GPI_IMR[3]; | |
52 | uint8_t GPI_EDER[3]; | |
53 | uint8_t GPI_LIR[3]; | |
54 | uint8_t GP_IARCR[3]; | |
55 | uint8_t GP_IARLCR[3]; | |
56 | uint8_t GPI_BCR[3]; | |
57 | uint16_t GPA_IARCR; | |
58 | uint16_t GPA_IARLCR; | |
59 | uint16_t CCR; | |
60 | uint16_t PLL2CR; | |
61 | uint32_t PLL1CR; | |
62 | uint8_t DIARCR; | |
63 | uint8_t DBOCR; | |
64 | uint8_t FER; | |
65 | uint16_t MCR; | |
66 | uint8_t CONFIG; | |
67 | uint8_t DEBUG; | |
68 | } scr; | |
69 | uint32_t gpio_dir; | |
70 | uint32_t gpio_level; | |
71 | uint32_t prev_level; | |
72 | qemu_irq handler[TC6393XB_GPIOS]; | |
73 | qemu_irq *gpio_in; | |
74 | }; | |
75 | ||
76 | qemu_irq *tc6393xb_gpio_in_get(struct tc6393xb_s *s) | |
77 | { | |
78 | return s->gpio_in; | |
79 | } | |
80 | ||
81 | static void tc6393xb_gpio_set(void *opaque, int line, int level) | |
82 | { | |
83 | // struct tc6393xb_s *s = opaque; | |
84 | ||
85 | if (line > TC6393XB_GPIOS) { | |
86 | printf("%s: No GPIO pin %i\n", __FUNCTION__, line); | |
87 | return; | |
88 | } | |
89 | ||
90 | // FIXME: how does the chip reflect the GPIO input level change? | |
91 | } | |
92 | ||
93 | void tc6393xb_gpio_out_set(struct tc6393xb_s *s, int line, | |
94 | qemu_irq handler) | |
95 | { | |
96 | if (line >= TC6393XB_GPIOS) { | |
97 | fprintf(stderr, "TC6393xb: no GPIO pin %d\n", line); | |
98 | return; | |
99 | } | |
100 | ||
101 | s->handler[line] = handler; | |
102 | } | |
103 | ||
104 | static void tc6393xb_gpio_handler_update(struct tc6393xb_s *s) | |
105 | { | |
106 | uint32_t level, diff; | |
107 | int bit; | |
108 | ||
109 | level = s->gpio_level & s->gpio_dir; | |
110 | ||
111 | for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { | |
112 | bit = ffs(diff) - 1; | |
113 | qemu_set_irq(s->handler[bit], (level >> bit) & 1); | |
114 | } | |
115 | ||
116 | s->prev_level = level; | |
117 | } | |
118 | ||
119 | #define SCR_REG_B(N) \ | |
120 | case SCR_ ##N: return s->scr.N | |
121 | #define SCR_REG_W(N) \ | |
122 | case SCR_ ##N: return s->scr.N; \ | |
123 | case SCR_ ##N + 1: return s->scr.N >> 8; | |
124 | #define SCR_REG_L(N) \ | |
125 | case SCR_ ##N: return s->scr.N; \ | |
126 | case SCR_ ##N + 1: return s->scr.N >> 8; \ | |
127 | case SCR_ ##N + 2: return s->scr.N >> 16; \ | |
128 | case SCR_ ##N + 3: return s->scr.N >> 24; | |
129 | #define SCR_REG_A(N) \ | |
130 | case SCR_ ##N(0): return s->scr.N[0]; \ | |
131 | case SCR_ ##N(1): return s->scr.N[1]; \ | |
132 | case SCR_ ##N(2): return s->scr.N[2] | |
133 | ||
134 | static uint32_t tc6393xb_readb(void *opaque, target_phys_addr_t addr) | |
135 | { | |
136 | struct tc6393xb_s *s = opaque; | |
137 | addr -= s->target_base; | |
138 | switch (addr) { | |
139 | case SCR_REVID: | |
140 | return 3; | |
141 | case SCR_REVID+1: | |
142 | return 0; | |
143 | SCR_REG_B(ISR); | |
144 | SCR_REG_B(IMR); | |
145 | SCR_REG_B(IRR); | |
146 | SCR_REG_W(GPER); | |
147 | SCR_REG_A(GPI_SR); | |
148 | SCR_REG_A(GPI_IMR); | |
149 | SCR_REG_A(GPI_EDER); | |
150 | SCR_REG_A(GPI_LIR); | |
151 | case SCR_GPO_DSR(0): | |
152 | case SCR_GPO_DSR(1): | |
153 | case SCR_GPO_DSR(2): | |
154 | return (s->gpio_level >> ((addr - SCR_GPO_DSR(0)) * 8)) & 0xff; | |
155 | case SCR_GPO_DOECR(0): | |
156 | case SCR_GPO_DOECR(1): | |
157 | case SCR_GPO_DOECR(2): | |
158 | return (s->gpio_dir >> ((addr - SCR_GPO_DOECR(0)) * 8)) & 0xff; | |
159 | SCR_REG_A(GP_IARCR); | |
160 | SCR_REG_A(GP_IARLCR); | |
161 | SCR_REG_A(GPI_BCR); | |
162 | SCR_REG_W(GPA_IARCR); | |
163 | SCR_REG_W(GPA_IARLCR); | |
164 | SCR_REG_W(CCR); | |
165 | SCR_REG_W(PLL2CR); | |
166 | SCR_REG_L(PLL1CR); | |
167 | SCR_REG_B(DIARCR); | |
168 | SCR_REG_B(DBOCR); | |
169 | SCR_REG_B(FER); | |
170 | SCR_REG_W(MCR); | |
171 | SCR_REG_B(CONFIG); | |
172 | SCR_REG_B(DEBUG); | |
173 | } | |
174 | fprintf(stderr, "tc6393xb: unhandled read at %08x\n", (uint32_t) addr); | |
175 | return 0; | |
176 | } | |
177 | #undef SCR_REG_B | |
178 | #undef SCR_REG_W | |
179 | #undef SCR_REG_L | |
180 | #undef SCR_REG_A | |
181 | ||
182 | #define SCR_REG_B(N) \ | |
183 | case SCR_ ##N: s->scr.N = value; break; | |
184 | #define SCR_REG_W(N) \ | |
185 | case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); break; \ | |
186 | case SCR_ ##N + 1: s->scr.N = (s->scr.N & 0xff) | (value << 8); break | |
187 | #define SCR_REG_L(N) \ | |
188 | case SCR_ ##N: s->scr.N = (s->scr.N & ~0xff) | (value & 0xff); break; \ | |
189 | case SCR_ ##N + 1: s->scr.N = (s->scr.N & ~(0xff << 8)) | (value & (0xff << 8)); break; \ | |
190 | case SCR_ ##N + 2: s->scr.N = (s->scr.N & ~(0xff << 16)) | (value & (0xff << 16)); break; \ | |
191 | case SCR_ ##N + 3: s->scr.N = (s->scr.N & ~(0xff << 24)) | (value & (0xff << 24)); break; | |
192 | #define SCR_REG_A(N) \ | |
193 | case SCR_ ##N(0): s->scr.N[0] = value; break; \ | |
194 | case SCR_ ##N(1): s->scr.N[1] = value; break; \ | |
195 | case SCR_ ##N(2): s->scr.N[2] = value; break | |
196 | ||
197 | static void tc6393xb_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) | |
198 | { | |
199 | struct tc6393xb_s *s = opaque; | |
200 | addr -= s->target_base; | |
201 | switch (addr) { | |
202 | SCR_REG_B(ISR); | |
203 | SCR_REG_B(IMR); | |
204 | SCR_REG_B(IRR); | |
205 | SCR_REG_W(GPER); | |
206 | SCR_REG_A(GPI_SR); | |
207 | SCR_REG_A(GPI_IMR); | |
208 | SCR_REG_A(GPI_EDER); | |
209 | SCR_REG_A(GPI_LIR); | |
210 | case SCR_GPO_DSR(0): | |
211 | case SCR_GPO_DSR(1): | |
212 | case SCR_GPO_DSR(2): | |
213 | s->gpio_level = (s->gpio_level & ~(0xff << ((addr - SCR_GPO_DSR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DSR(0))*8)); | |
214 | tc6393xb_gpio_handler_update(s); | |
215 | break; | |
216 | case SCR_GPO_DOECR(0): | |
217 | case SCR_GPO_DOECR(1): | |
218 | case SCR_GPO_DOECR(2): | |
219 | s->gpio_dir = (s->gpio_dir & ~(0xff << ((addr - SCR_GPO_DOECR(0))*8))) | ((value & 0xff) << ((addr - SCR_GPO_DOECR(0))*8)); | |
220 | tc6393xb_gpio_handler_update(s); | |
221 | break; | |
222 | SCR_REG_A(GP_IARCR); | |
223 | SCR_REG_A(GP_IARLCR); | |
224 | SCR_REG_A(GPI_BCR); | |
225 | SCR_REG_W(GPA_IARCR); | |
226 | SCR_REG_W(GPA_IARLCR); | |
227 | SCR_REG_W(CCR); | |
228 | SCR_REG_W(PLL2CR); | |
229 | SCR_REG_L(PLL1CR); | |
230 | SCR_REG_B(DIARCR); | |
231 | SCR_REG_B(DBOCR); | |
232 | SCR_REG_B(FER); | |
233 | SCR_REG_W(MCR); | |
234 | SCR_REG_B(CONFIG); | |
235 | SCR_REG_B(DEBUG); | |
236 | default: | |
237 | fprintf(stderr, "tc6393xb: unhandled write at %08x: %02x\n", | |
238 | (uint32_t) addr, value & 0xff); | |
239 | break; | |
240 | } | |
241 | } | |
242 | #undef SCR_REG_B | |
243 | #undef SCR_REG_W | |
244 | #undef SCR_REG_L | |
245 | #undef SCR_REG_A | |
246 | ||
247 | static uint32_t tc6393xb_readw(void *opaque, target_phys_addr_t addr) | |
248 | { | |
249 | return (tc6393xb_readb(opaque, addr) & 0xff) | | |
250 | (tc6393xb_readb(opaque, addr + 1) << 8); | |
251 | } | |
252 | ||
253 | static uint32_t tc6393xb_readl(void *opaque, target_phys_addr_t addr) | |
254 | { | |
255 | return (tc6393xb_readb(opaque, addr) & 0xff) | | |
256 | ((tc6393xb_readb(opaque, addr + 1) & 0xff) << 8) | | |
257 | ((tc6393xb_readb(opaque, addr + 2) & 0xff) << 16) | | |
258 | ((tc6393xb_readb(opaque, addr + 3) & 0xff) << 24); | |
259 | } | |
260 | ||
261 | static void tc6393xb_writew(void *opaque, target_phys_addr_t addr, uint32_t value) | |
262 | { | |
263 | tc6393xb_writeb(opaque, addr, value); | |
264 | tc6393xb_writeb(opaque, addr + 1, value >> 8); | |
265 | } | |
266 | ||
267 | static void tc6393xb_writel(void *opaque, target_phys_addr_t addr, uint32_t value) | |
268 | { | |
269 | tc6393xb_writeb(opaque, addr, value); | |
270 | tc6393xb_writeb(opaque, addr + 1, value >> 8); | |
271 | tc6393xb_writeb(opaque, addr + 2, value >> 16); | |
272 | tc6393xb_writeb(opaque, addr + 3, value >> 24); | |
273 | } | |
274 | ||
275 | struct tc6393xb_s *tc6393xb_init(uint32_t base, qemu_irq irq) | |
276 | { | |
277 | int iomemtype; | |
278 | struct tc6393xb_s *s; | |
279 | CPUReadMemoryFunc *tc6393xb_readfn[] = { | |
280 | tc6393xb_readb, | |
281 | tc6393xb_readw, | |
282 | tc6393xb_readl, | |
283 | }; | |
284 | CPUWriteMemoryFunc *tc6393xb_writefn[] = { | |
285 | tc6393xb_writeb, | |
286 | tc6393xb_writew, | |
287 | tc6393xb_writel, | |
288 | }; | |
289 | ||
290 | s = (struct tc6393xb_s *) qemu_mallocz(sizeof(struct tc6393xb_s)); | |
291 | s->target_base = base; | |
292 | s->gpio_in = qemu_allocate_irqs(tc6393xb_gpio_set, s, TC6393XB_GPIOS); | |
293 | ||
294 | iomemtype = cpu_register_io_memory(0, tc6393xb_readfn, | |
295 | tc6393xb_writefn, s); | |
296 | cpu_register_physical_memory(s->target_base, 0x200000, iomemtype); | |
297 | ||
298 | return s; | |
299 | } |