|
1 /* |
|
2 * Copyright (c) 2006-2008 Openedhand Ltd. |
|
3 * Written by Andrzej Zaborowski <balrog@zabor.org> |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or |
|
6 * modify it under the terms of the GNU General Public License as |
|
7 * published by the Free Software Foundation; either version 2 or |
|
8 * (at your option) version 3 of the License. |
|
9 * |
|
10 * This program is distributed in the hope that it will be useful, |
|
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
13 * GNU General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU General Public License |
|
16 * along with this program; if not, write to the Free Software |
|
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
|
18 * MA 02111-1307 USA |
|
19 */ |
|
20 #include "hw.h" |
|
21 #include "pxa.h" |
|
22 #include "sharpsl.h" |
|
23 |
|
24 #undef REG_FMT |
|
25 #if TARGET_PHYS_ADDR_BITS == 32 |
|
26 #define REG_FMT "0x%02x" |
|
27 #else |
|
28 #define REG_FMT "0x%02lx" |
|
29 #endif |
|
30 |
|
31 /* SCOOP devices */ |
|
32 |
|
33 struct scoop_info_s { |
|
34 qemu_irq handler[16]; |
|
35 qemu_irq *in; |
|
36 uint16_t status; |
|
37 uint16_t power; |
|
38 uint32_t gpio_level; |
|
39 uint32_t gpio_dir; |
|
40 uint32_t prev_level; |
|
41 |
|
42 uint16_t mcr; |
|
43 uint16_t cdr; |
|
44 uint16_t ccr; |
|
45 uint16_t irr; |
|
46 uint16_t imr; |
|
47 uint16_t isr; |
|
48 }; |
|
49 |
|
50 #define SCOOP_MCR 0x00 |
|
51 #define SCOOP_CDR 0x04 |
|
52 #define SCOOP_CSR 0x08 |
|
53 #define SCOOP_CPR 0x0c |
|
54 #define SCOOP_CCR 0x10 |
|
55 #define SCOOP_IRR_IRM 0x14 |
|
56 #define SCOOP_IMR 0x18 |
|
57 #define SCOOP_ISR 0x1c |
|
58 #define SCOOP_GPCR 0x20 |
|
59 #define SCOOP_GPWR 0x24 |
|
60 #define SCOOP_GPRR 0x28 |
|
61 |
|
62 static inline void scoop_gpio_handler_update(struct scoop_info_s *s) { |
|
63 uint32_t level, diff; |
|
64 int bit; |
|
65 level = s->gpio_level & s->gpio_dir; |
|
66 |
|
67 for (diff = s->prev_level ^ level; diff; diff ^= 1 << bit) { |
|
68 bit = ffs(diff) - 1; |
|
69 qemu_set_irq(s->handler[bit], (level >> bit) & 1); |
|
70 } |
|
71 |
|
72 s->prev_level = level; |
|
73 } |
|
74 |
|
75 static uint32_t scoop_readb(void *opaque, target_phys_addr_t addr) |
|
76 { |
|
77 struct scoop_info_s *s = (struct scoop_info_s *) opaque; |
|
78 |
|
79 switch (addr) { |
|
80 case SCOOP_MCR: |
|
81 return s->mcr; |
|
82 case SCOOP_CDR: |
|
83 return s->cdr; |
|
84 case SCOOP_CSR: |
|
85 return s->status; |
|
86 case SCOOP_CPR: |
|
87 return s->power; |
|
88 case SCOOP_CCR: |
|
89 return s->ccr; |
|
90 case SCOOP_IRR_IRM: |
|
91 return s->irr; |
|
92 case SCOOP_IMR: |
|
93 return s->imr; |
|
94 case SCOOP_ISR: |
|
95 return s->isr; |
|
96 case SCOOP_GPCR: |
|
97 return s->gpio_dir; |
|
98 case SCOOP_GPWR: |
|
99 case SCOOP_GPRR: |
|
100 return s->gpio_level; |
|
101 default: |
|
102 zaurus_printf("Bad register offset " REG_FMT "\n", addr); |
|
103 } |
|
104 |
|
105 return 0; |
|
106 } |
|
107 |
|
108 static void scoop_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) |
|
109 { |
|
110 struct scoop_info_s *s = (struct scoop_info_s *) opaque; |
|
111 value &= 0xffff; |
|
112 |
|
113 switch (addr) { |
|
114 case SCOOP_MCR: |
|
115 s->mcr = value; |
|
116 break; |
|
117 case SCOOP_CDR: |
|
118 s->cdr = value; |
|
119 break; |
|
120 case SCOOP_CPR: |
|
121 s->power = value; |
|
122 if (value & 0x80) |
|
123 s->power |= 0x8040; |
|
124 break; |
|
125 case SCOOP_CCR: |
|
126 s->ccr = value; |
|
127 break; |
|
128 case SCOOP_IRR_IRM: |
|
129 s->irr = value; |
|
130 break; |
|
131 case SCOOP_IMR: |
|
132 s->imr = value; |
|
133 break; |
|
134 case SCOOP_ISR: |
|
135 s->isr = value; |
|
136 break; |
|
137 case SCOOP_GPCR: |
|
138 s->gpio_dir = value; |
|
139 scoop_gpio_handler_update(s); |
|
140 break; |
|
141 case SCOOP_GPWR: |
|
142 case SCOOP_GPRR: /* GPRR is probably R/O in real HW */ |
|
143 s->gpio_level = value & s->gpio_dir; |
|
144 scoop_gpio_handler_update(s); |
|
145 break; |
|
146 default: |
|
147 zaurus_printf("Bad register offset " REG_FMT "\n", addr); |
|
148 } |
|
149 } |
|
150 |
|
151 static CPUReadMemoryFunc *scoop_readfn[] = { |
|
152 scoop_readb, |
|
153 scoop_readb, |
|
154 scoop_readb, |
|
155 }; |
|
156 static CPUWriteMemoryFunc *scoop_writefn[] = { |
|
157 scoop_writeb, |
|
158 scoop_writeb, |
|
159 scoop_writeb, |
|
160 }; |
|
161 |
|
162 void scoop_gpio_set(void *opaque, int line, int level) |
|
163 { |
|
164 struct scoop_info_s *s = (struct scoop_info_s *) s; |
|
165 |
|
166 if (level) |
|
167 s->gpio_level |= (1 << line); |
|
168 else |
|
169 s->gpio_level &= ~(1 << line); |
|
170 } |
|
171 |
|
172 qemu_irq *scoop_gpio_in_get(struct scoop_info_s *s) |
|
173 { |
|
174 return s->in; |
|
175 } |
|
176 |
|
177 void scoop_gpio_out_set(struct scoop_info_s *s, int line, |
|
178 qemu_irq handler) { |
|
179 if (line >= 16) { |
|
180 fprintf(stderr, "No GPIO pin %i\n", line); |
|
181 exit(-1); |
|
182 } |
|
183 |
|
184 s->handler[line] = handler; |
|
185 } |
|
186 |
|
187 static void scoop_save(QEMUFile *f, void *opaque) |
|
188 { |
|
189 struct scoop_info_s *s = (struct scoop_info_s *) opaque; |
|
190 qemu_put_be16s(f, &s->status); |
|
191 qemu_put_be16s(f, &s->power); |
|
192 qemu_put_be32s(f, &s->gpio_level); |
|
193 qemu_put_be32s(f, &s->gpio_dir); |
|
194 qemu_put_be32s(f, &s->prev_level); |
|
195 qemu_put_be16s(f, &s->mcr); |
|
196 qemu_put_be16s(f, &s->cdr); |
|
197 qemu_put_be16s(f, &s->ccr); |
|
198 qemu_put_be16s(f, &s->irr); |
|
199 qemu_put_be16s(f, &s->imr); |
|
200 qemu_put_be16s(f, &s->isr); |
|
201 } |
|
202 |
|
203 static int scoop_load(QEMUFile *f, void *opaque, int version_id) |
|
204 { |
|
205 uint16_t dummy; |
|
206 struct scoop_info_s *s = (struct scoop_info_s *) opaque; |
|
207 qemu_get_be16s(f, &s->status); |
|
208 qemu_get_be16s(f, &s->power); |
|
209 qemu_get_be32s(f, &s->gpio_level); |
|
210 qemu_get_be32s(f, &s->gpio_dir); |
|
211 qemu_get_be32s(f, &s->prev_level); |
|
212 qemu_get_be16s(f, &s->mcr); |
|
213 qemu_get_be16s(f, &s->cdr); |
|
214 qemu_get_be16s(f, &s->ccr); |
|
215 qemu_get_be16s(f, &s->irr); |
|
216 qemu_get_be16s(f, &s->imr); |
|
217 qemu_get_be16s(f, &s->isr); |
|
218 if (version_id < 1) |
|
219 qemu_get_be16s(f, &dummy); |
|
220 |
|
221 return 0; |
|
222 } |
|
223 |
|
224 struct scoop_info_s *scoop_init(struct pxa2xx_state_s *cpu, |
|
225 int instance, |
|
226 target_phys_addr_t target_base) { |
|
227 int iomemtype; |
|
228 struct scoop_info_s *s; |
|
229 |
|
230 s = (struct scoop_info_s *) |
|
231 qemu_mallocz(sizeof(struct scoop_info_s)); |
|
232 memset(s, 0, sizeof(struct scoop_info_s)); |
|
233 |
|
234 s->status = 0x02; |
|
235 s->in = qemu_allocate_irqs(scoop_gpio_set, s, 16); |
|
236 iomemtype = cpu_register_io_memory(0, scoop_readfn, |
|
237 scoop_writefn, s); |
|
238 cpu_register_physical_memory(target_base, 0x1000, iomemtype); |
|
239 register_savevm("scoop", instance, 1, scoop_save, scoop_load, s); |
|
240 |
|
241 return s; |
|
242 } |
|
243 |
|
244 /* Write the bootloader parameters memory area. */ |
|
245 |
|
246 #define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a) |
|
247 |
|
248 static struct __attribute__ ((__packed__)) sl_param_info { |
|
249 uint32_t comadj_keyword; |
|
250 int32_t comadj; |
|
251 |
|
252 uint32_t uuid_keyword; |
|
253 char uuid[16]; |
|
254 |
|
255 uint32_t touch_keyword; |
|
256 int32_t touch_xp; |
|
257 int32_t touch_yp; |
|
258 int32_t touch_xd; |
|
259 int32_t touch_yd; |
|
260 |
|
261 uint32_t adadj_keyword; |
|
262 int32_t adadj; |
|
263 |
|
264 uint32_t phad_keyword; |
|
265 int32_t phadadj; |
|
266 } zaurus_bootparam = { |
|
267 .comadj_keyword = MAGIC_CHG('C', 'M', 'A', 'D'), |
|
268 .comadj = 125, |
|
269 .uuid_keyword = MAGIC_CHG('U', 'U', 'I', 'D'), |
|
270 .uuid = { -1 }, |
|
271 .touch_keyword = MAGIC_CHG('T', 'U', 'C', 'H'), |
|
272 .touch_xp = -1, |
|
273 .adadj_keyword = MAGIC_CHG('B', 'V', 'A', 'D'), |
|
274 .adadj = -1, |
|
275 .phad_keyword = MAGIC_CHG('P', 'H', 'A', 'D'), |
|
276 .phadadj = 0x01, |
|
277 }; |
|
278 |
|
279 void sl_bootparam_write(uint32_t ptr) |
|
280 { |
|
281 /* FIXME: This is broken if it spans multiple RAM regions. */ |
|
282 memcpy(host_ram_addr(ptr), &zaurus_bootparam, |
|
283 sizeof(struct sl_param_info)); |
|
284 } |