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