OMAP LPGs (LED pulse generators).

OMAP MPUI bridge config register.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3710 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
balrog 2007-11-20 11:15:27 +00:00
parent d07b4d0ea7
commit f9d43072e2
2 changed files with 189 additions and 2 deletions

186
hw/omap.c
View file

@ -4626,6 +4626,184 @@ void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave)
slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0];
}
/* LED Pulse Generators */
struct omap_lpg_s {
target_phys_addr_t base;
QEMUTimer *tm;
uint8_t control;
uint8_t power;
int64_t on;
int64_t period;
int clk;
int cycle;
};
static void omap_lpg_tick(void *opaque)
{
struct omap_lpg_s *s = opaque;
if (s->cycle)
qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->period - s->on);
else
qemu_mod_timer(s->tm, qemu_get_clock(rt_clock) + s->on);
s->cycle = !s->cycle;
printf("%s: LED is %s\n", __FUNCTION__, s->cycle ? "on" : "off");
}
static void omap_lpg_update(struct omap_lpg_s *s)
{
int64_t on, period = 1, ticks = 1000;
static const int per[8] = { 1, 2, 4, 8, 12, 16, 20, 24 };
if (~s->control & (1 << 6)) /* LPGRES */
on = 0;
else if (s->control & (1 << 7)) /* PERM_ON */
on = period;
else {
period = muldiv64(ticks, per[s->control & 7], /* PERCTRL */
256 / 32);
on = (s->clk && s->power) ? muldiv64(ticks,
per[(s->control >> 3) & 7], 256) : 0; /* ONCTRL */
}
qemu_del_timer(s->tm);
if (on == period && s->on < s->period)
printf("%s: LED is on\n", __FUNCTION__);
else if (on == 0 && s->on)
printf("%s: LED is off\n", __FUNCTION__);
else if (on && (on != s->on || period != s->period)) {
s->cycle = 0;
s->on = on;
s->period = period;
omap_lpg_tick(s);
return;
}
s->on = on;
s->period = period;
}
static void omap_lpg_reset(struct omap_lpg_s *s)
{
s->control = 0x00;
s->power = 0x00;
s->clk = 1;
omap_lpg_update(s);
}
static uint32_t omap_lpg_read(void *opaque, target_phys_addr_t addr)
{
struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
int offset = addr & OMAP_MPUI_REG_MASK;
switch (offset) {
case 0x00: /* LCR */
return s->control;
case 0x04: /* PMR */
return s->power;
}
OMAP_BAD_REG(addr);
return 0;
}
static void omap_lpg_write(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
int offset = addr & OMAP_MPUI_REG_MASK;
switch (offset) {
case 0x00: /* LCR */
if (~value & (1 << 6)) /* LPGRES */
omap_lpg_reset(s);
s->control = value & 0xff;
omap_lpg_update(s);
return;
case 0x04: /* PMR */
s->power = value & 0x01;
omap_lpg_update(s);
return;
default:
OMAP_BAD_REG(addr);
return;
}
}
static CPUReadMemoryFunc *omap_lpg_readfn[] = {
omap_lpg_read,
omap_badwidth_read8,
omap_badwidth_read8,
};
static CPUWriteMemoryFunc *omap_lpg_writefn[] = {
omap_lpg_write,
omap_badwidth_write8,
omap_badwidth_write8,
};
static void omap_lpg_clk_update(void *opaque, int line, int on)
{
struct omap_lpg_s *s = (struct omap_lpg_s *) opaque;
s->clk = on;
omap_lpg_update(s);
}
struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk)
{
int iomemtype;
struct omap_lpg_s *s = (struct omap_lpg_s *)
qemu_mallocz(sizeof(struct omap_lpg_s));
s->base = base;
s->tm = qemu_new_timer(rt_clock, omap_lpg_tick, s);
omap_lpg_reset(s);
iomemtype = cpu_register_io_memory(0, omap_lpg_readfn,
omap_lpg_writefn, s);
cpu_register_physical_memory(s->base, 0x800, iomemtype);
omap_clk_adduser(clk, qemu_allocate_irqs(omap_lpg_clk_update, s, 1)[0]);
return s;
}
/* MPUI Peripheral Bridge configuration */
static uint32_t omap_mpui_io_read(void *opaque, target_phys_addr_t addr)
{
if (addr == OMAP_MPUI_BASE) /* CMR */
return 0xfe4d;
OMAP_BAD_REG(addr);
return 0;
}
static CPUReadMemoryFunc *omap_mpui_io_readfn[] = {
omap_badwidth_read16,
omap_mpui_io_read,
omap_badwidth_read16,
};
static CPUWriteMemoryFunc *omap_mpui_io_writefn[] = {
omap_badwidth_write16,
omap_badwidth_write16,
omap_badwidth_write16,
};
static void omap_setup_mpui_io(struct omap_mpu_state_s *mpu)
{
int iomemtype = cpu_register_io_memory(0, omap_mpui_io_readfn,
omap_mpui_io_writefn, mpu);
cpu_register_physical_memory(OMAP_MPUI_BASE, 0x7fff, iomemtype);
}
/* General chip reset */
static void omap_mpu_reset(void *opaque)
{
@ -4663,6 +4841,8 @@ static void omap_mpu_reset(void *opaque)
omap_mcbsp_reset(mpu->mcbsp1);
omap_mcbsp_reset(mpu->mcbsp2);
omap_mcbsp_reset(mpu->mcbsp3);
omap_lpg_reset(mpu->led[0]);
omap_lpg_reset(mpu->led[1]);
cpu_reset(mpu->env);
}
@ -4846,6 +5026,9 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX],
&s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck"));
s->led[0] = omap_lpg_init(0xfffbd000, omap_findclk(s, "clk32-kHz"));
s->led[1] = omap_lpg_init(0xfffbd800, omap_findclk(s, "clk32-kHz"));
/* Register mappings not currenlty implemented:
* MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310)
* MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310)
@ -4855,8 +5038,6 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
* FAC fffba800 - fffbafff
* HDQ/1-Wire fffbc000 - fffbc7ff
* TIPB switches fffbc800 - fffbcfff
* LED1 fffbd000 - fffbd7ff
* LED2 fffbd800 - fffbdfff
* Mailbox fffcf000 - fffcf7ff
* Local bus IF fffec100 - fffec1ff
* Local bus MMU fffec200 - fffec2ff
@ -4864,6 +5045,7 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size,
*/
omap_setup_dsp_mapping(omap15xx_dsp_mm);
omap_setup_mpui_io(s);
qemu_register_reset(omap_mpu_reset, s);

View file

@ -508,6 +508,9 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
qemu_irq *irq, qemu_irq *dma, omap_clk clk);
void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave);
struct omap_lpg_s;
struct omap_lpg_s *omap_lpg_init(target_phys_addr_t base, omap_clk clk);
/* omap_lcdc.c */
struct omap_lcd_panel_s;
void omap_lcdc_reset(struct omap_lcd_panel_s *s);
@ -598,6 +601,8 @@ struct omap_mpu_state_s {
struct omap_mcbsp_s *mcbsp2;
struct omap_lpg_s *led[2];
/* MPU private TIPB peripherals */
struct omap_intr_handler_s *ih[2];