📄 omap.c.svn-base
字号:
QEMUTimer *tm; struct omap_mpu_state_s *mpu; target_phys_addr_t base; omap_clk clk; int64_t delay; uint32_t drq; enum omap_dma_model model; int omap_3_1_mapping_disabled; uint16_t gcr; int run_count; int chans; struct omap_dma_channel_s ch[16]; struct omap_dma_lcd_channel_s lcd_ch;};/* Interrupts */#define TIMEOUT_INTR (1 << 0)#define EVENT_DROP_INTR (1 << 1)#define HALF_FRAME_INTR (1 << 2)#define END_FRAME_INTR (1 << 3)#define LAST_FRAME_INTR (1 << 4)#define END_BLOCK_INTR (1 << 5)#define SYNC (1 << 6)static void omap_dma_interrupts_update(struct omap_dma_s *s){ struct omap_dma_channel_s *ch = s->ch; int i; if (s->omap_3_1_mapping_disabled) { for (i = 0; i < s->chans; i ++, ch ++) if (ch->status) qemu_irq_raise(ch->irq); } else { /* First three interrupts are shared between two channels each. */ for (i = 0; i < 6; i ++, ch ++) { if (ch->status || (ch->sibling && ch->sibling->status)) qemu_irq_raise(ch->irq); } }}static void omap_dma_channel_load(struct omap_dma_s *s, struct omap_dma_channel_s *ch){ struct omap_dma_reg_set_s *a = &ch->active_set; int i; int omap_3_1 = !ch->omap_3_1_compatible_disable; /* * TODO: verify address ranges and alignment * TODO: port endianness */ a->src = ch->addr[0]; a->dest = ch->addr[1]; a->frames = ch->frames; a->elements = ch->elements; a->frame = 0; a->element = 0; if (unlikely(!ch->elements || !ch->frames)) { printf("%s: bad DMA request\n", __FUNCTION__); return; } for (i = 0; i < 2; i ++) switch (ch->mode[i]) { case constant: a->elem_delta[i] = 0; a->frame_delta[i] = 0; break; case post_incremented: a->elem_delta[i] = ch->data_type; a->frame_delta[i] = 0; break; case single_index: a->elem_delta[i] = ch->data_type + ch->element_index[omap_3_1 ? 0 : i] - 1; a->frame_delta[i] = 0; break; case double_index: a->elem_delta[i] = ch->data_type + ch->element_index[omap_3_1 ? 0 : i] - 1; a->frame_delta[i] = ch->frame_index[omap_3_1 ? 0 : i] - ch->element_index[omap_3_1 ? 0 : i]; break; default: break; }}static void omap_dma_activate_channel(struct omap_dma_s *s, struct omap_dma_channel_s *ch){ if (!ch->active) { ch->active = 1; if (ch->sync) ch->status |= SYNC; s->run_count ++; } if (s->delay && !qemu_timer_pending(s->tm)) qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);}static void omap_dma_deactivate_channel(struct omap_dma_s *s, struct omap_dma_channel_s *ch){ /* Update cpc */ ch->cpc = ch->active_set.dest & 0xffff; if (ch->pending_request && !ch->waiting_end_prog) { /* Don't deactivate the channel */ ch->pending_request = 0; return; } /* Don't deactive the channel if it is synchronized and the DMA request is active */ if (ch->sync && (s->drq & (1 << ch->sync))) return; if (ch->active) { ch->active = 0; ch->status &= ~SYNC; s->run_count --; } if (!s->run_count) qemu_del_timer(s->tm);}static void omap_dma_enable_channel(struct omap_dma_s *s, struct omap_dma_channel_s *ch){ if (!ch->enable) { ch->enable = 1; ch->waiting_end_prog = 0; omap_dma_channel_load(s, ch); if ((!ch->sync) || (s->drq & (1 << ch->sync))) omap_dma_activate_channel(s, ch); }}static void omap_dma_disable_channel(struct omap_dma_s *s, struct omap_dma_channel_s *ch){ if (ch->enable) { ch->enable = 0; /* Discard any pending request */ ch->pending_request = 0; omap_dma_deactivate_channel(s, ch); }}static void omap_dma_channel_end_prog(struct omap_dma_s *s, struct omap_dma_channel_s *ch){ if (ch->waiting_end_prog) { ch->waiting_end_prog = 0; if (!ch->sync || ch->pending_request) { ch->pending_request = 0; omap_dma_activate_channel(s, ch); } }}static void omap_dma_enable_3_1_mapping(struct omap_dma_s *s){ s->omap_3_1_mapping_disabled = 0; s->chans = 9;}static void omap_dma_disable_3_1_mapping(struct omap_dma_s *s){ s->omap_3_1_mapping_disabled = 1; s->chans = 16;}static void omap_dma_process_request(struct omap_dma_s *s, int request){ int channel; int drop_event = 0; struct omap_dma_channel_s *ch = s->ch; for (channel = 0; channel < s->chans; channel ++, ch ++) { if (ch->enable && ch->sync == request) { if (!ch->active) omap_dma_activate_channel(s, ch); else if (!ch->pending_request) ch->pending_request = 1; else { /* Request collision */ /* Second request received while processing other request */ ch->status |= EVENT_DROP_INTR; drop_event = 1; } } } if (drop_event) omap_dma_interrupts_update(s);}static void omap_dma_channel_run(struct omap_dma_s *s){ int n = s->chans; uint16_t status; uint8_t value[4]; struct omap_dma_port_if_s *src_p, *dest_p; struct omap_dma_reg_set_s *a; struct omap_dma_channel_s *ch; for (ch = s->ch; n; n --, ch ++) { if (!ch->active) continue; a = &ch->active_set; src_p = &s->mpu->port[ch->port[0]]; dest_p = &s->mpu->port[ch->port[1]]; if ((!ch->constant_fill && !src_p->addr_valid(s->mpu, a->src)) || (!dest_p->addr_valid(s->mpu, a->dest))) {#if 0 /* Bus time-out */ if (ch->interrupts & TIMEOUT_INTR) ch->status |= TIMEOUT_INTR; omap_dma_deactivate_channel(s, ch); continue;#endif printf("%s: Bus time-out in DMA%i operation\n", __FUNCTION__, s->chans - n); } status = ch->status; while (status == ch->status && ch->active) { /* Transfer a single element */ /* FIXME: check the endianness */ if (!ch->constant_fill) cpu_physical_memory_read(a->src, value, ch->data_type); else *(uint32_t *) value = ch->color; if (!ch->transparent_copy || *(uint32_t *) value != ch->color) cpu_physical_memory_write(a->dest, value, ch->data_type); a->src += a->elem_delta[0]; a->dest += a->elem_delta[1]; a->element ++; /* If the channel is element synchronized, deactivate it */ if (ch->sync && !ch->fs && !ch->bs) omap_dma_deactivate_channel(s, ch); /* If it is the last frame, set the LAST_FRAME interrupt */ if (a->element == 1 && a->frame == a->frames - 1) if (ch->interrupts & LAST_FRAME_INTR) ch->status |= LAST_FRAME_INTR; /* If the half of the frame was reached, set the HALF_FRAME interrupt */ if (a->element == (a->elements >> 1)) if (ch->interrupts & HALF_FRAME_INTR) ch->status |= HALF_FRAME_INTR; if (a->element == a->elements) { /* End of Frame */ a->element = 0; a->src += a->frame_delta[0]; a->dest += a->frame_delta[1]; a->frame ++; /* If the channel is frame synchronized, deactivate it */ if (ch->sync && ch->fs) omap_dma_deactivate_channel(s, ch); /* If the channel is async, update cpc */ if (!ch->sync) ch->cpc = a->dest & 0xffff; /* Set the END_FRAME interrupt */ if (ch->interrupts & END_FRAME_INTR) ch->status |= END_FRAME_INTR; if (a->frame == a->frames) { /* End of Block */ /* Disable the channel */ if (ch->omap_3_1_compatible_disable) { omap_dma_disable_channel(s, ch); if (ch->link_enabled) omap_dma_enable_channel(s, &s->ch[ch->link_next_ch]); } else { if (!ch->auto_init) omap_dma_disable_channel(s, ch); else if (ch->repeat || ch->end_prog) omap_dma_channel_load(s, ch); else { ch->waiting_end_prog = 1; omap_dma_deactivate_channel(s, ch); } } if (ch->interrupts & END_BLOCK_INTR) ch->status |= END_BLOCK_INTR; } } } } omap_dma_interrupts_update(s); if (s->run_count && s->delay) qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);}static void omap_dma_reset(struct omap_dma_s *s){ int i; qemu_del_timer(s->tm); s->gcr = 0x0004; s->drq = 0x00000000; s->run_count = 0; s->lcd_ch.src = emiff; s->lcd_ch.condition = 0; s->lcd_ch.interrupts = 0; s->lcd_ch.dual = 0; omap_dma_enable_3_1_mapping(s); for (i = 0; i < s->chans; i ++) { memset(&s->ch[i].burst, 0, sizeof(s->ch[i].burst)); memset(&s->ch[i].port, 0, sizeof(s->ch[i].port)); memset(&s->ch[i].mode, 0, sizeof(s->ch[i].mode)); memset(&s->ch[i].elements, 0, sizeof(s->ch[i].elements)); memset(&s->ch[i].frames, 0, sizeof(s->ch[i].frames)); memset(&s->ch[i].frame_index, 0, sizeof(s->ch[i].frame_index)); memset(&s->ch[i].element_index, 0, sizeof(s->ch[i].element_index)); memset(&s->ch[i].data_type, 0, sizeof(s->ch[i].data_type)); memset(&s->ch[i].transparent_copy, 0, sizeof(s->ch[i].transparent_copy)); memset(&s->ch[i].constant_fill, 0, sizeof(s->ch[i].constant_fill)); memset(&s->ch[i].color, 0, sizeof(s->ch[i].color)); memset(&s->ch[i].end_prog, 0, sizeof(s->ch[i].end_prog)); memset(&s->ch[i].repeat, 0, sizeof(s->ch[i].repeat)); memset(&s->ch[i].auto_init, 0, sizeof(s->ch[i].auto_init)); memset(&s->ch[i].link_enabled, 0, sizeof(s->ch[i].link_enabled)); memset(&s->ch[i].link_next_ch, 0, sizeof(s->ch[i].link_next_ch)); s->ch[i].interrupts = 0x0003; memset(&s->ch[i].status, 0, sizeof(s->ch[i].status)); memset(&s->ch[i].active, 0, sizeof(s->ch[i].active)); memset(&s->ch[i].enable, 0, sizeof(s->ch[i].enable)); memset(&s->ch[i].sync, 0, sizeof(s->ch[i].sync)); memset(&s->ch[i].pending_request, 0, sizeof(s->ch[i].pending_request)); memset(&s->ch[i].waiting_end_prog, 0, sizeof(s->ch[i].waiting_end_prog)); memset(&s->ch[i].cpc, 0, sizeof(s->ch[i].cpc)); memset(&s->ch[i].fs, 0, sizeof(s->ch[i].fs)); memset(&s->ch[i].bs, 0, sizeof(s->ch[i].bs)); memset(&s->ch[i].omap_3_1_compatible_disable, 0, sizeof(s->ch[i].omap_3_1_compatible_disable)); memset(&s->ch[i].active_set, 0, sizeof(s->ch[i].active_set)); memset(&s->ch[i].priority, 0, sizeof(s->ch[i].priority)); memset(&s->ch[i].interleave_disabled, 0, sizeof(s->ch[i].interleave_disabled)); memset(&s->ch[i].type, 0, sizeof(s->ch[i].type)); }}static int omap_dma_ch_reg_read(struct omap_dma_s *s, struct omap_dma_channel_s *ch, int reg, uint16_t *value){ switch (reg) { case 0x00: /* SYS_DMA_CSDP_CH0 */ *value = (ch->burst[1] << 14) | (ch->pack[1] << 13) | (ch->port[1] << 9) | (ch->burst[0] << 7) | (ch->pack[0] << 6) | (ch->port[0] << 2) | (ch->data_type >> 1); break; case 0x02: /* SYS_DMA_CCR_CH0 */ if (s->model == omap_dma_3_1) *value = 0 << 10; /* FIFO_FLUSH reads as 0 */ else *value = ch->omap_3_1_compatible_disable << 10; *value |= (ch->mode[1] << 14) | (ch->mode[0] << 12) | (ch->end_prog << 11) | (ch->repeat << 9) | (ch->auto_init << 8) | (ch->enable << 7) | (ch->priority << 6) | (ch->fs << 5) | ch->sync; break; case 0x04: /* SYS_DMA_CICR_CH0 */ *value = ch->interrupts; break; case 0x06: /* SYS_DMA_CSR_CH0 */ *value = ch->status; ch->status &= SYNC; if (!ch->omap_3_1_compatible_disable && ch->sibling) { *value |= (ch->sibling->status & 0x3f) << 6; ch->sibling->status &= SYNC; } qemu_irq_lower(ch->irq); break; case 0x08: /* SYS_DMA_CSSA_L_CH0 */ *value = ch->addr[0] & 0x0000ffff; break; case 0x0a: /* SYS_DMA_CSSA_U_CH0 */ *value = ch->addr[0] >> 16; break; case 0x0c: /* SYS_DMA_CDSA_L_CH0 */ *value = ch->addr[1] & 0x0000ffff; break; case 0x0e: /* SYS_DMA_CDSA_U_CH0 */ *value = ch->addr[1] >> 16; break; case 0x10: /* SYS_DMA_CEN_CH0 */ *value = ch->elements; break; case 0x12: /* SYS_DMA_CFN_CH0 */ *value = ch->frames; break; case 0x14: /* SYS_DMA_CFI_CH0 */ *value = ch->frame_index[0]; break; case 0x16: /* SYS_DMA_CEI_CH0 */ *value = ch->element_index[0]; break; case 0x18: /* SYS_DMA_CPC_CH0 or DMA_CSAC */ if (ch->omap_3_1_compatible_disable) *value = ch->active_set.src & 0xffff; /* CSAC */ else *value = ch->cpc; break; case 0x1a: /* DMA_CDAC */ *value = ch->active_set.dest & 0xffff; /* CDAC */ break; case 0x1c: /* DMA_CDEI */ *value = ch->element_index[1]; break; case 0x1e: /* DMA_CDFI */ *value = ch->frame_index[1]; break; case 0x20: /* DMA_COLOR_L */ *value = ch->color & 0xffff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -