2 * QEMU JZ Soc emulation glue code
4 * Copyright (c) 2009 yajin (yajin@vm-kernel.org)
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
28 static inline void glue(jz4740_tcu_time_sync
,
29 TCU_INDEX
) (struct jz4740_tcu_s
* s
)
34 if ((!(s
->tsr
& (1 << TCU_INDEX
))) && (s
->ter
& (1 << TCU_INDEX
))
35 && (s
->freq
[TCU_INDEX
] != 0))
37 //debug_out(DEBUG_TCU, "jz4740_tcu_time_sync%x \n", TCU_INDEX);
38 /*first enable timer */
39 if (s
->time
[TCU_INDEX
] == 0)
41 s
->time
[TCU_INDEX
] = qemu_get_clock(vm_clock
);
42 s
->tcnt
[TCU_INDEX
] = 0;
45 distance
= qemu_get_clock(vm_clock
) - s
->time
[TCU_INDEX
];
46 //debug_out(DEBUG_TCU,
47 // "s->freq[TCU_INDEX] %d s->prescale[TCU_INDEX] %d \n",
48 // s->freq[TCU_INDEX], s->prescale[TCU_INDEX]);
49 // debug_out(DEBUG_TCU, "distance %lld s->time[TCU_INDEX] %lld \n",
50 // distance, s->time[TCU_INDEX]);
51 //temp = muldiv64(distance,(s->freq[TCU_INDEX]/s->prescale[TCU_INDEX]),ticks_per_sec);
52 temp
= muldiv64(distance
, 46875, ticks_per_sec
);
55 /*distance is too short */
56 s
->tcnt
[TCU_INDEX
] += temp
;
57 s
->time
[TCU_INDEX
] = qemu_get_clock(vm_clock
);
61 /*distance is too short.
62 * Do not sync timer this timer.
66 //printf("%lld distance %lld \n",muldiv64(distance,(s->freq[TCU_INDEX]/s->prescale[TCU_INDEX]),ticks_per_sec),distance);
68 if (s
->tcnt
[TCU_INDEX
] >= 0x10000)
69 s
->tcnt
[TCU_INDEX
] = 0x0;
75 static inline void glue(jz4740_tcu_start_half
,
76 TCU_INDEX
) (struct jz4740_tcu_s
* s
)
78 int64_t next
= qemu_get_clock(vm_clock
);
81 /*The timer has not beed initialized */
82 if (!s
->half_timer
[TCU_INDEX
])
85 if ((!(s
->tsr
& (1 << (TCU_INDEX
+16)))) && (s
->ter
& (1 << (TCU_INDEX
+16)))
86 && (s
->freq
[TCU_INDEX
] != 0))
88 glue(jz4740_tcu_time_sync
, TCU_INDEX
) (s
);
89 /*calculate next fire time */
91 (s
->tdhr
[TCU_INDEX
] - s
->tcnt
[TCU_INDEX
]) * s
->prescale
[TCU_INDEX
];
92 next
+= muldiv64(count
, ticks_per_sec
, s
->freq
[TCU_INDEX
]);
93 qemu_mod_timer(s
->half_timer
[TCU_INDEX
], next
);
97 qemu_del_timer(s
->half_timer
[TCU_INDEX
]);
101 static inline void glue(jz4740_tcu_start_full
,
102 TCU_INDEX
) (struct jz4740_tcu_s
* s
)
104 int64_t next
= qemu_get_clock(vm_clock
);
107 /*The timer has not beed initialized */
108 if (!s
->full_timer
[TCU_INDEX
])
111 debug_out(DEBUG_TCU
, "s->tsr %d s->ter %d s->freq[TCU_INDEX] %d \n",
112 s
->tsr
, s
->ter
,s
->freq
[TCU_INDEX
]);
113 if ((!(s
->tsr
& (1 << TCU_INDEX
))) && (s
->ter
& (1 << TCU_INDEX
))
114 && (s
->freq
[TCU_INDEX
] != 0))
116 glue(jz4740_tcu_time_sync
, TCU_INDEX
) (s
);
117 /*calculate next fire time */
119 (s
->tdfr
[TCU_INDEX
] - s
->tcnt
[TCU_INDEX
]) * s
->prescale
[TCU_INDEX
];
120 next
+= muldiv64(count
, ticks_per_sec
, s
->freq
[TCU_INDEX
]);
121 qemu_mod_timer(s
->full_timer
[TCU_INDEX
], next
);
122 debug_out(DEBUG_TCU
, "s->tdfr[TCU_INDEX] %d s->tcnt[TCU_INDEX] %d next %lld \n",
123 s
->tdfr
[TCU_INDEX
] , s
->tcnt
[TCU_INDEX
] ,next
);
126 qemu_del_timer(s
->full_timer
[TCU_INDEX
]);
131 * TCNT will reset to 0 if it reach to TDFR.
132 * So for the half compare, the next fire count is (TDFR-TDHR) + TDHR
135 static void glue(jz4740_tcu_half_cb
, TCU_INDEX
) (void *opaque
)
137 struct jz4740_tcu_s
*s
= (struct jz4740_tcu_s
*) opaque
;
138 int64_t next
= qemu_get_clock(vm_clock
);
141 if ((!(s
->tsr
& (1 << TCU_INDEX
))) && (s
->ter
& (1 << TCU_INDEX
))
142 && (s
->freq
[TCU_INDEX
] != 0))
144 count
= s
->tdfr
[TCU_INDEX
] * s
->prescale
[TCU_INDEX
];
145 next
+= muldiv64(count
, ticks_per_sec
, s
->freq
[TCU_INDEX
]);
146 qemu_mod_timer(s
->half_timer
[TCU_INDEX
], next
);
147 s
->tfr
|= 1 << (16 + TCU_INDEX
);
148 jz4740_tcu_update_interrupt(s
);
149 s
->tcnt
[TCU_INDEX
] = s
->tdhr
[TCU_INDEX
];
150 s
->time
[TCU_INDEX
] = qemu_get_clock(vm_clock
);
153 qemu_del_timer(s
->half_timer
[TCU_INDEX
]);
157 static void glue(jz4740_tcu_full_cb
, TCU_INDEX
) (void *opaque
)
159 struct jz4740_tcu_s
*s
= (struct jz4740_tcu_s
*) opaque
;
160 int64_t next
= qemu_get_clock(vm_clock
);
163 if ((!(s
->tsr
& (1 << TCU_INDEX
))) && (s
->ter
& (1 << TCU_INDEX
))
164 && (s
->freq
[TCU_INDEX
] != 0))
166 count
= s
->tdfr
[TCU_INDEX
] * s
->prescale
[TCU_INDEX
];
167 next
+= muldiv64(count
, ticks_per_sec
, s
->freq
[TCU_INDEX
]);
168 qemu_mod_timer(s
->full_timer
[TCU_INDEX
], next
);
169 s
->tfr
|= 1 << TCU_INDEX
;
170 jz4740_tcu_update_interrupt(s
);
171 s
->tcnt
[TCU_INDEX
] = 0;
172 s
->time
[TCU_INDEX
] = qemu_get_clock(vm_clock
);
175 qemu_del_timer(s
->full_timer
[TCU_INDEX
]);
178 static uint32_t glue(jz4740_tcu_read
, TCU_INDEX
) (void *opaque
,
179 target_phys_addr_t addr
)
181 struct jz4740_tcu_s
*s
= (struct jz4740_tcu_s
*) opaque
;
183 debug_out(DEBUG_TCU
, "jz4740_tcu_read%x addr %x\n", TCU_INDEX
, addr
);
184 addr
-= 0x40 + TCU_INDEX
* 0x10;
189 return s
->tdfr
[TCU_INDEX
];
191 return s
->tdhr
[TCU_INDEX
];
193 glue(jz4740_tcu_time_sync
, TCU_INDEX
) (s
);
194 return s
->tcnt
[TCU_INDEX
];
196 return s
->tcsr
[TCU_INDEX
];
198 cpu_abort(s
->soc
->env
,
199 "jz4740_tcu_read undefined addr "JZ_FMT_plx
" timer %x \n", addr
,
205 static void glue(jz4740_tcu_write
, TCU_INDEX
) (void *opaque
,
206 target_phys_addr_t addr
,
209 struct jz4740_tcu_s
*s
= (struct jz4740_tcu_s
*) opaque
;
211 debug_out(DEBUG_TCU
, "jz4740_tcu_write%x addr "JZ_FMT_plx
" value %x \n", TCU_INDEX
,
213 addr
-= 0x40 + TCU_INDEX
* 0x10;
219 s
->tdfr
[TCU_INDEX
] = value
& 0xffff;
220 glue(jz4740_tcu_start_full
, TCU_INDEX
) (s
);
223 /*TDHR*/ s
->tdhr
[TCU_INDEX
] = value
& 0xffff;
224 glue(jz4740_tcu_start_half
, TCU_INDEX
) (s
);
227 /*TCNT*/ s
->tcnt
[TCU_INDEX
] = value
& 0xffff;
228 s
->time
[TCU_INDEX
] = qemu_get_clock(vm_clock
);
229 glue(jz4740_tcu_start_half
, TCU_INDEX
) (s
);
230 glue(jz4740_tcu_start_full
, TCU_INDEX
) (s
);
233 s
->tcsr
[TCU_INDEX
] = value
& 0x3bf;
237 s
->freq
[TCU_INDEX
] = jz_clk_getrate(jz_findclk(s
->soc
, "pclk"));
240 s
->freq
[TCU_INDEX
] = jz_clk_getrate(jz_findclk(s
->soc
, "osc_32K"));
244 jz_clk_getrate(jz_findclk(s
->soc
, "osc_extal"));
247 s
->freq
[TCU_INDEX
] = 0x0;
250 s
->prescale
[TCU_INDEX
] = 1 << (((value
& 0x38) >> 3) * 2);
251 glue(jz4740_tcu_start_half
, TCU_INDEX
) (s
);
252 glue(jz4740_tcu_start_full
, TCU_INDEX
) (s
);
255 cpu_abort(s
->soc
->env
,
256 "jz4740_tcu_write undefined addr "JZ_FMT_plx
" timer %x \n", addr
,
263 static CPUReadMemoryFunc
*glue(jz4740_tcu_readfn
, TCU_INDEX
)[] =
265 jz4740_badwidth_read16
,
266 glue(jz4740_tcu_read
, TCU_INDEX
), jz4740_badwidth_read16
,};
268 static CPUWriteMemoryFunc
*glue(jz4740_tcu_writefn
, TCU_INDEX
)[] =
270 jz4740_badwidth_write16
,
271 glue(jz4740_tcu_write
, TCU_INDEX
), jz4740_badwidth_write16
,};
273 static void glue(jz4740_tcu_init
, TCU_INDEX
) (struct jz_state_s
* soc
,
274 struct jz4740_tcu_s
* s
)
278 s
->half_timer
[TCU_INDEX
] =
279 qemu_new_timer(vm_clock
, glue(jz4740_tcu_half_cb
, TCU_INDEX
), s
);
280 s
->full_timer
[TCU_INDEX
] =
281 qemu_new_timer(vm_clock
, glue(jz4740_tcu_full_cb
, TCU_INDEX
), s
);
284 cpu_register_io_memory(0, glue(jz4740_tcu_readfn
, TCU_INDEX
),
285 glue(jz4740_tcu_writefn
, TCU_INDEX
), s
);
286 cpu_register_physical_memory(s
->base
+ 0x00000040 + TCU_INDEX
* 0x10,
287 0x00000010, iomemtype
);
295 #ifdef JZ4740_LCD_PANEL
299 # define PIXEL_TYPE uint8_t
300 #elif DEPTH == 15 || DEPTH == 16
302 # define PIXEL_TYPE uint16_t
305 # define PIXEL_TYPE uint32_t
308 # define PIXEL_TYPE uint32_t
310 # error unsupport depth
316 static void glue(draw_line2_
, DEPTH
) (uint8_t * d
, const uint8_t * s
, int width
,
317 const uint16_t * pal
)
323 v
= ldub_raw((void *) s
);
324 r
= (pal
[v
& 3] >> 4) & 0xf0;
325 g
= pal
[v
& 3] & 0xf0;
326 b
= (pal
[v
& 3] << 4) & 0xf0;
327 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
330 r
= (pal
[v
& 3] >> 4) & 0xf0;
331 g
= pal
[v
& 3] & 0xf0;
332 b
= (pal
[v
& 3] << 4) & 0xf0;
333 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
336 r
= (pal
[v
& 3] >> 4) & 0xf0;
337 g
= pal
[v
& 3] & 0xf0;
338 b
= (pal
[v
& 3] << 4) & 0xf0;
339 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
342 r
= (pal
[v
& 3] >> 4) & 0xf0;
343 g
= pal
[v
& 3] & 0xf0;
344 b
= (pal
[v
& 3] << 4) & 0xf0;
345 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
356 static void glue(draw_line4_
, DEPTH
) (uint8_t * d
, const uint8_t * s
, int width
,
357 const uint16_t * pal
)
363 v
= ldub_raw((void *) s
);
364 r
= (pal
[v
& 0xf] >> 4) & 0xf0;
365 g
= pal
[v
& 0xf] & 0xf0;
366 b
= (pal
[v
& 0xf] << 4) & 0xf0;
367 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
370 r
= (pal
[v
& 0xf] >> 4) & 0xf0;
371 g
= pal
[v
& 0xf] & 0xf0;
372 b
= (pal
[v
& 0xf] << 4) & 0xf0;
373 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
384 static void glue(draw_line8_
, DEPTH
) (uint8_t * d
, const uint8_t * s
, int width
,
385 const uint16_t * pal
)
391 v
= ldub_raw((void *) s
);
392 r
= (pal
[v
] >> 4) & 0xf0;
394 b
= (pal
[v
] << 4) & 0xf0;
395 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
399 while (--width
!= 0);
406 static void glue(draw_line16_
, DEPTH
) (uint8_t * d
, const uint8_t * s
,
407 int width
, const uint16_t * pal
)
409 #if DEPTH == 16 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
410 memcpy(d
, s
, width
* 2);
417 v
= lduw_raw((void *) s
);
421 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
425 while (--width
!= 0);
430 * 24-bit colour. JZ4740 uses 4 bytes to store 18/24 bit color.
432 static void glue(draw_line24_
, DEPTH
) (uint8_t * d
, const uint8_t * s
,
433 int width
, const uint16_t * pal
)
435 #if DEPTH == 32 && defined(WORDS_BIGENDIAN) == defined(TARGET_WORDS_BIGENDIAN)
436 memcpy(d
, s
, width
* 4);
443 v
= ldl_raw((void *) s
);
444 r
= (v
>> 16) & 0xff;
447 ((PIXEL_TYPE
*) d
)[0] = glue(rgb_to_pixel
, DEPTH
) (r
, g
, b
);
451 while (--width
!= 0);
455 static jz4740_lcd_fn_t
glue(jz4740_lcd_draw_fn_
, DEPTH
)[6] =
457 NULL
, /*0x0 *//*1 bit per pixel */
458 (jz4740_lcd_fn_t
) glue(draw_line2_
, DEPTH
), /*0x1 *//*2 bit per pixel */
459 (jz4740_lcd_fn_t
) glue(draw_line4_
, DEPTH
), /*0x2 *//*4 bit per pixel */
460 (jz4740_lcd_fn_t
) glue(draw_line8_
, DEPTH
), /*0x3 *//*8 bit per pixel */
461 (jz4740_lcd_fn_t
) glue(draw_line16_
, DEPTH
), /*0x4 *//*15/16 bit per pixel */
462 (jz4740_lcd_fn_t
) glue(draw_line24_
, DEPTH
), /*0x5 *//*18/24 bit per pixel */