Send commitlog mailing list submissions to
[email protected]
To subscribe or unsubscribe via the World Wide Web, visit
http://lists.openmoko.org/mailman/listinfo/commitlog
or, via email, send a message with subject or body 'help' to
[EMAIL PROTECTED]
You can reach the person managing the list at
[EMAIL PROTECTED]
When replying, please edit your Subject line so it is more specific
than "Re: Contents of commitlog digest..."
Today's Topics:
1. r3750 - trunk/src/host/qemu-neo1973/hw ([EMAIL PROTECTED])
2. r3751 - trunk/src/host/qemu-neo1973/hw ([EMAIL PROTECTED])
3. r3752 - trunk/src/host/qemu-neo1973/hw ([EMAIL PROTECTED])
4. r3753 - trunk/src/host/qemu-neo1973/hw ([EMAIL PROTECTED])
--- Begin Message ---
Author: andrew
Date: 2007-12-28 19:13:57 +0100 (Fri, 28 Dec 2007)
New Revision: 3750
Modified:
trunk/src/host/qemu-neo1973/hw/neo1973.c
Log:
Preliminary LIS302DL accelerometers in the GTA02F.
Modified: trunk/src/host/qemu-neo1973/hw/neo1973.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-12-28 07:16:20 UTC (rev
3749)
+++ trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-12-28 18:13:57 UTC (rev
3750)
@@ -87,6 +87,7 @@
i2c_slave *pmu;
i2c_slave *wm;
i2c_slave *lcm;
+ i2c_slave *accel[2];
CharDriverState *modem;
CharDriverState *gps;
QEMUTimer *modem_timer;
@@ -344,9 +345,207 @@
return &s->i2c;
}
+/* LIS302DL "piccolo" motion sensor/accelerometer */
+struct piccolo_s {
+ i2c_slave i2c;
+ int firstbyte;
+
+ qemu_irq intr[2];
+
+ uint8_t regs[0x40];
+ int reg;
+
+ QEMUTimer *sample;
+};
+
+void piccolo_reset(i2c_slave *i2c)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+
+ memset(s->regs, 0, sizeof(s->regs));
+ s->regs[0x0f] = 0x3b; /* Who_Am_I */
+ s->regs[0x20] = 0x07; /* Ctrl_Reg1 */
+}
+
+static void piccolo_sample_sched(struct piccolo_s *s)
+{
+ int rate = (s->regs[0x20] & (1 << 7)) ? 400 : 100; /* DR */
+
+ qemu_mod_timer(s->sample,
+ qemu_get_clock(vm_clock) + ticks_per_sec / rate);
+}
+
+static void piccolo_sample_tick(void *opaque)
+{
+ struct piccolo_s *s = (struct piccolo_s *) opaque;
+
+ /* TODO */
+ piccolo_sample_sched(s);
+}
+
+static void piccolo_sample_update(struct piccolo_s *s)
+{
+ if (!(s->regs[0x20] & 7)) /* Xen | Yen | Zen */
+ qemu_del_timer(s->sample);
+ else if (!qemu_timer_pending(s->sample))
+ piccolo_sample_sched(s);
+}
+
+static void piccolo_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+
+ if (event == I2C_START_SEND)
+ s->firstbyte = 1;
+}
+
+static int piccolo_rx(i2c_slave *i2c)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+ int reg = s->reg;
+
+ if (reg >= 0x80) {
+ reg -= 0x80;
+ s->reg ++;
+ } else
+ s->reg = -1;
+
+ switch (reg) {
+ case 0x00 ... 0x0e:
+ case 0x10 ... 0x1f:
+ case 0x2e ... 0x2f:
+ case 0x0f: /* Who_Am_I */
+ case 0x20: /* Ctrl_Reg1 */
+ case 0x21: /* Ctrl_Reg2 */
+ case 0x22: /* Ctrl_Reg3 */
+ case 0x23: /* HP_filter_reset */
+ case 0x27: /* Status_Reg */
+ case 0x29: /* OutX */
+ case 0x2b: /* OutY */
+ case 0x2d: /* OutZ */
+ case 0x30: /* FF_WU_CFG_1 */
+ case 0x31: /* FF_WU_SRC_1 */
+ case 0x32: /* FF_WU_THS_1 */
+ case 0x33: /* FF_WU_DURATION_1 */
+ case 0x34: /* FF_WU_CFG_2 */
+ case 0x35: /* FF_WU_SRC_2 */
+ case 0x36: /* FF_WU_THS_2 */
+ case 0x37: /* FF_WU_DURATION_2 */
+ case 0x38: /* CLICK_CFG */
+ case 0x39: /* CLICK_SRC */
+ case 0x3b: /* CLICK_THSY_X */
+ case 0x3c: /* CLICK_THSZ */
+ case 0x3d: /* CLICK_timelimit */
+ case 0x3e: /* CLICK_latency */
+ case 0x3f: /* CLICK_window */
+ break;
+ default:
+ fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+ return 0x00;
+ }
+
+ return s->regs[reg];
+}
+
+static int piccolo_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct piccolo_s *s = (struct piccolo_s *) i2c;
+ int reg = s->reg;
+
+ if (s->firstbyte) {
+ s->firstbyte = 0;
+ s->reg = data;
+ return 0;
+ }
+
+ if (reg >= 0x80) {
+ reg -= 0x80;
+ s->reg ++;
+ }
+
+ switch (reg) {
+ case 0x00 ... 0x0e:
+ case 0x10 ... 0x1f:
+ case 0x2e ... 0x2f:
+ fprintf(stderr, "%s: write to a \"do not modify\" register %02x\n",
+ __FUNCTION__, s->reg);
+ fprintf(stderr, "%s: may cause permanent damage!\n", __FUNCTION__);
+ s->regs[reg] = data;
+ break;
+ case 0x20: /* Ctrl_Reg1 */
+ s->regs[reg] = data;
+ if (data & (3 << 3))
+ fprintf(stderr, "%s: Self-Test Enable attempt\n", __FUNCTION__);
+ piccolo_sample_update(s);
+ break;
+
+ case 0x21: /* Ctrl_Reg2 */
+ case 0x22: /* Ctrl_Reg3 */
+ case 0x30: /* FF_WU_CFG_1 */
+ case 0x32: /* FF_WU_THS_1 */
+ case 0x33: /* FF_WU_DURATION_1 */
+ case 0x34: /* FF_WU_CFG_2 */
+ case 0x36: /* FF_WU_THS_2 */
+ case 0x37: /* FF_WU_DURATION_2 */
+ case 0x38: /* CLICK_CFG */
+ case 0x39: /* CLICK_SRC */
+ case 0x3b: /* CLICK_THSY_X */
+ case 0x3c: /* CLICK_THSZ */
+ case 0x3d: /* CLICK_timelimit */
+ case 0x3e: /* CLICK_latency */
+ case 0x3f: /* CLICK_window */
+ /* TODO */
+ s->regs[reg] = data;
+ break;
+
+ default:
+ fprintf(stderr, "%s: unknown register %02x\n", __FUNCTION__, reg);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void piccolo_save(QEMUFile *f, void *opaque)
+{
+ struct piccolo_s *s = (struct piccolo_s *) opaque;
+
+ qemu_put_buffer(f, s->regs, sizeof(s->regs));
+ i2c_slave_save(f, &s->i2c);
+}
+
+static int piccolo_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct piccolo_s *s = (struct piccolo_s *) opaque;
+
+ qemu_get_buffer(f, s->regs, sizeof(s->regs));
+ i2c_slave_load(f, &s->i2c);
+ return 0;
+}
+
+i2c_slave *lis302dl_init(i2c_bus *bus, qemu_irq int1, qemu_irq int2)
+{
+ struct piccolo_s *s = (struct piccolo_s *)
+ i2c_slave_init(bus, 0, sizeof(struct piccolo_s));
+ s->i2c.event = piccolo_event;
+ s->i2c.send = piccolo_tx;
+ s->i2c.recv = piccolo_rx;
+
+ s->intr[0] = int1;
+ s->intr[1] = int2;
+ s->sample = qemu_new_timer(vm_clock, piccolo_sample_tick, s);
+
+ piccolo_reset(&s->i2c);
+ register_savevm("lis302dl", 0, 0, piccolo_save, piccolo_load, s);
+
+ return &s->i2c;
+}
+
/* I2C bus */
#define NEO_PMU_ADDR 0x08
#define NEO_WM_ADDR 0x1a
+#define NEO_ACCEL_ADDR0 0x1c
+#define NEO_ACCEL_ADDR1 0x1d
#define NEO_AMP_ADDR 0x7c /* ADR wired to low */
static void neo_i2c_setup(struct neo_board_s *s)
@@ -370,6 +569,14 @@
s->lcm = lm4857_init(bus);
i2c_set_slave_address(s->lcm, NEO_AMP_ADDR);
+ /* Attach two LIS302DL slaves to the bus */
+ if (s->id == NEO1973_GTA02 || s->id == NEO1973_GTA02F) {
+ s->accel[0] = lis302dl_init(bus, 0, 0); /* TODO: connect IRQs */
+ s->accel[1] = lis302dl_init(bus, 0, 0); /* TODO: connect IRQs */
+ i2c_set_slave_address(s->accel[0], NEO_ACCEL_ADDR0);
+ i2c_set_slave_address(s->accel[1], NEO_ACCEL_ADDR1);
+ }
+
#ifdef HAS_AUDIO
audio = AUD_init();
if (!audio)
--- End Message ---
--- Begin Message ---
Author: andrew
Date: 2007-12-28 21:50:54 +0100 (Fri, 28 Dec 2007)
New Revision: 3751
Modified:
trunk/src/host/qemu-neo1973/hw/ar6000.c
Log:
AR6000 interrupt logic. Fix reset.
Modified: trunk/src/host/qemu-neo1973/hw/ar6000.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-28 18:13:57 UTC (rev
3750)
+++ trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-28 20:50:54 UTC (rev
3751)
@@ -26,6 +26,7 @@
#include "hw.h"
#include "net.h"
+#include "qemu-timer.h"
#include "sd.h"
#include "pcmcia.h"
@@ -944,6 +945,7 @@
struct ar6k_s {
struct sdio_s sd;
NICInfo *nd;
+
struct {
uint8_t host_int_stat;
uint8_t cpu_int_stat;
@@ -956,9 +958,10 @@
uint8_t cpu_int_stat_ena;
uint8_t err_int_stat_ena;
uint8_t cnt_int_stat_ena;
- uint8_t cnt[8];
- uint32_t cnt_dec[8];
+ uint8_t cnt[4];
+ uint32_t cnt_tx[4];
uint8_t scratch[8];
+ uint8_t wlan_int;
uint8_t mbox[0x800 * 4];
int mbox_count[4];
@@ -966,22 +969,94 @@
struct {
int done;
} bmi;
+
+ QEMUTimer *cnt_irq_update;
+
uint8_t cis[0];
};
+static inline void ar6k_hif_intr_update(struct ar6k_s *s)
+{
+ qemu_set_irq(s->sd.func_irq[0],
+ !!(s->hif.host_int_stat & s->hif.int_stat_ena));
+}
+
+static void ar6k_hif_error_intr_update(struct ar6k_s *s)
+{
+ uint8_t orig = s->hif.host_int_stat;
+
+ if (s->hif.error_int_stat & s->hif.err_int_stat_ena)
+ s->hif.host_int_stat |= 1 << 7; /* STATUS_ERROR
*/
+ else
+ s->hif.host_int_stat &= ~(1 << 7); /* STATUS_ERROR */
+
+ if (orig != s->hif.host_int_stat)
+ ar6k_hif_intr_update(s);
+}
+
+static void ar6k_hif_cpu_intr_update(struct ar6k_s *s)
+{
+ uint8_t orig = s->hif.host_int_stat;
+
+ if (s->hif.cpu_int_stat & s->hif.cpu_int_stat_ena)
+ s->hif.host_int_stat |= 1 << 6; /* STATUS_CPU */
+ else
+ s->hif.host_int_stat &= ~(1 << 6); /* STATUS_CPU */
+
+ if (orig != s->hif.host_int_stat)
+ ar6k_hif_intr_update(s);
+}
+
+static void ar6k_hif_counter_intr_update(struct ar6k_s *s)
+{
+ uint8_t orig = s->hif.host_int_stat;
+
+ if (s->hif.counter_int_stat & s->hif.cnt_int_stat_ena)
+ s->hif.host_int_stat |= 1 << 4; /*
STATUS_COUNTER */
+ else
+ s->hif.host_int_stat &= ~(1 << 4); /* STATUS_COUNTER */
+
+ if (orig != s->hif.host_int_stat)
+ ar6k_hif_intr_update(s);
+}
+
+static void ar6k_hif_counter_intr_sched(struct ar6k_s *s)
+{
+ qemu_mod_timer(s->cnt_irq_update, qemu_get_clock(vm_clock) +
+ (ticks_per_sec >> 6));
+}
+
+static void ar6k_hif_cnt_irq_tick(void *opaque)
+{
+ struct ar6k_s *s = (void *) opaque;
+
+ ar6k_hif_counter_intr_update(s);
+}
+
static void ar6k_bmi_reset(struct ar6k_s *s)
{
int i;
- for (i = 0; i < 8; i ++) {
+ for (i = 0; i < 4; i ++) {
s->hif.cnt[i] = 0x00;
- s->hif.cnt_dec[i] = 0xff;
+ s->hif.cnt_tx[i] = 0xff;
+ s->hif.mbox_count[i] = 0;
}
- for (i = 0; i < 4; i ++)
- s->hif.mbox_count[i] = 0;
+ s->bmi.done = 0;
- s->bmi.done = 0;
+ s->hif.host_int_stat = 0x00;
+ s->hif.cpu_int_stat = 0x00;
+ s->hif.error_int_stat = 0x00;
+ s->hif.counter_int_stat = 0xf0;
+ s->hif.int_stat_ena = 0x00;
+ s->hif.cpu_int_stat_ena = 0x00;
+ s->hif.err_int_stat_ena = 0x00;
+ s->hif.cnt_int_stat_ena = 0x00;
+
+ ar6k_hif_cpu_intr_update(s);
+ ar6k_hif_error_intr_update(s);
+ ar6k_hif_counter_intr_update(s);
}
enum {
@@ -1044,10 +1119,27 @@
return;
}
- s->hif.cnt_dec[4] = 0xff;
- s->hif.cnt[4] = rlen;
+ s->hif.cnt[0] = rlen;
}
+static void ar6k_hif_txcredit_reset(struct ar6k_s *s, int mbox)
+{
+ s->hif.cnt_tx[mbox] = 0;
+ if (!(s->hif.counter_int_stat & (1 << mbox))) {
+ s->hif.counter_int_stat |= 1 << mbox;
+ ar6k_hif_counter_intr_sched(s);
+ }
+}
+
+static void ar6k_hif_txcredit_grant(struct ar6k_s *s, int mbox)
+{
+ s->hif.cnt_tx[mbox] = 0xff;
+ if (!(s->hif.counter_int_stat & (1 << (mbox + 4)))) {
+ s->hif.counter_int_stat |= 1 << (mbox + 4);
+ ar6k_hif_counter_intr_sched(s);
+ }
+}
+
#define AR6K_HOST_INT_STAT 0x400
#define AR6K_CPU_INT_STAT 0x401
#define AR6K_ERROR_INT_STAT 0x402
@@ -1063,7 +1155,8 @@
#define AR6K_ERROR_STAT_ENABLE 0x41a
#define AR6K_COUNTER_INT_STAT_ENABLE 0x41b
#define AR6K_COUNT 0x420
-#define AR6K_COUNT_DEC 0x440
+#define AR6K_COUNT_RESET 0x440
+#define AR6K_COUNT_DEC 0x450
#define AR6K_SCRATCH 0x460
#define AR6K_FIFO_TIMEOUT 0x468
#define AR6K_FIFO_TIMEOUT_ENABLE 0x469
@@ -1089,6 +1182,30 @@
int mbox;
switch (addr) {
+ case AR6K_HOST_INT_STAT:
+ if (s->hif.host_int_stat & value) {
+ s->hif.host_int_stat &= ~value;
+ ar6k_hif_intr_update(s);
+ }
+ break;
+ case AR6K_CPU_INT_STAT:
+ if (s->hif.cpu_int_stat & value) {
+ s->hif.cpu_int_stat &= ~value;
+ ar6k_hif_cpu_intr_update(s);
+ }
+ break;
+ case AR6K_ERROR_INT_STAT:
+ if (s->hif.error_int_stat & value) {
+ s->hif.error_int_stat &= ~value;
+ ar6k_hif_error_intr_update(s);
+ }
+ break;
+ case AR6K_COUNTER_INT_STAT:
+ if (s->hif.counter_int_stat & value) {
+ s->hif.counter_int_stat &= ~value;
+ ar6k_hif_counter_intr_update(s);
+ }
+ break;
case AR6K_MBOX_FRAME:
s->hif.mbox_frame = value;
break;
@@ -1108,16 +1225,28 @@
s->hif.rx_la[3] = value;
break;
case AR6K_INT_STAT_ENABLE:
- s->hif.int_stat_ena = value;
+ if (s->hif.int_stat_ena ^ value) {
+ s->hif.int_stat_ena = value;
+ ar6k_hif_intr_update(s);
+ }
break;
case AR6K_CPU_INT_STAT_ENABLE:
- s->hif.cpu_int_stat_ena = value;
+ if (s->hif.cpu_int_stat_ena ^ value) {
+ s->hif.cpu_int_stat_ena = value;
+ ar6k_hif_cpu_intr_update(s);
+ }
break;
case AR6K_ERROR_STAT_ENABLE:
- s->hif.err_int_stat_ena = value;
+ if (s->hif.err_int_stat_ena ^ value) {
+ s->hif.err_int_stat_ena = value;
+ ar6k_hif_error_intr_update(s);
+ }
break;
case AR6K_COUNTER_INT_STAT_ENABLE:
- s->hif.cnt_int_stat_ena = value;
+ if (s->hif.cnt_int_stat_ena ^ value) {
+ s->hif.cnt_int_stat_ena = value;
+ ar6k_hif_counter_intr_sched(s);
+ }
break;
case AR6K_SCRATCH ... (AR6K_SCRATCH + 7):
s->hif.scratch[addr - AR6K_SCRATCH] = value;
@@ -1127,25 +1256,35 @@
case AR6K_DISABLE_SLEEP:
case AR6K_LOCAL_BUS_ENDIAN:
case AR6K_LOCAL_BUS:
+ goto bad_reg;
+
case AR6K_INT_WLAN:
+ s->hif.wlan_int = value;
+ if (value)
+ fprintf(stderr, "%s: WLAN interrupt\n", __FUNCTION__);
+ break;
+
case AR6K_WINDOW_DATA:
case AR6K_WRITE_ADDR:
case AR6K_READ_ADDR:
case AR6K_SPI_CONFIG:
goto bad_reg;
+
case AR6K_HIF_MBOX_BASE ... AR6K_HIF_MBOX_END:
mbox = (addr - AR6K_HIF_MBOX_BASE) >> 11;
s->hif.mbox[addr - AR6K_HIF_MBOX_BASE] = value;
s->hif.mbox_count[mbox] ++;
- /* XXX how do we know when a BMI command is executed? */
- if (mbox == 0 && !s->bmi.done) {
- s->hif.cnt_dec[4] = 0x00;
- s->hif.cnt[4] = 0x00;
- if ((addr & 0x7ff) == 0x7ff) {
+ /* XXX how else do we know when a command is executed? */
+ if ((addr & 0x7ff) == 0x7ff) {
+ ar6k_hif_txcredit_reset(s, mbox);
+ if (mbox == 0 && !s->bmi.done) {
ar6k_bmi_write(s, s->hif.mbox + (mbox << 11),
- s->hif.mbox_count[0]);
- s->hif.mbox_count[mbox] = 0;
+ s->hif.mbox_count[mbox]);
+ } else {
+ /* TODO */
}
+ s->hif.mbox_count[mbox] = 0;
+ ar6k_hif_txcredit_grant(s, mbox);
}
break;
default:
@@ -1157,6 +1296,8 @@
static uint8_t ar6k_hif_read(struct ar6k_s *s, uint32_t addr)
{
+ int mbox = 0;
+
switch (addr) {
case AR6K_HOST_INT_STAT:
return s->hif.host_int_stat;
@@ -1166,8 +1307,10 @@
return s->hif.error_int_stat;
case AR6K_COUNTER_INT_STAT:
return s->hif.counter_int_stat;
+
case AR6K_MBOX_FRAME:
return s->hif.mbox_frame;
+
case AR6K_RX_LOOKAHEAD_VALID:
return s->hif.rx_la_valid;
case AR6K_RX_LOOKAHEAD0:
@@ -1178,6 +1321,7 @@
return s->hif.rx_la[2];
case AR6K_RX_LOOKAHEAD3:
return s->hif.rx_la[3];
+
case AR6K_INT_STAT_ENABLE:
return s->hif.int_stat_ena;
case AR6K_CPU_INT_STAT_ENABLE:
@@ -1186,25 +1330,41 @@
return s->hif.err_int_stat_ena;
case AR6K_COUNTER_INT_STAT_ENABLE:
return s->hif.cnt_int_stat_ena;
- case AR6K_COUNT ... (AR6K_COUNT + 0x7):
- return s->hif.cnt[addr - AR6K_COUNT];
- case AR6K_COUNT_DEC + 0x00:
- case AR6K_COUNT_DEC + 0x04:
- case AR6K_COUNT_DEC + 0x08:
- case AR6K_COUNT_DEC + 0x0c:
- case AR6K_COUNT_DEC + 0x10:
- case AR6K_COUNT_DEC + 0x14:
- case AR6K_COUNT_DEC + 0x18:
- case AR6K_COUNT_DEC + 0x1c:
- return s->hif.cnt_dec[(addr - AR6K_COUNT_DEC) >> 2];
+
+ case (AR6K_COUNT + 0x4) ... (AR6K_COUNT + 0x7):
+ /* XXX What's at (AR6K_COUNT + 0x0) ... (AR6K_COUNT + 0x3)? */
+ /* FIXME clear some interrupts etc */
+ return s->hif.cnt[addr - AR6K_COUNT - 4];
+
+ case AR6K_COUNT_RESET + 0xc: mbox ++;
+ case AR6K_COUNT_RESET + 0x8: mbox ++;
+ case AR6K_COUNT_RESET + 0x4: mbox ++;
+ case AR6K_COUNT_RESET + 0x0:
+ if (s->hif.counter_int_stat & (1 << mbox)) {
+ s->hif.counter_int_stat &= ~(1 << mbox);
+ ar6k_hif_counter_intr_update(s);
+ }
+ return s->hif.cnt_tx[mbox];
+
+ case AR6K_COUNT_DEC + 0xc: mbox ++;
+ case AR6K_COUNT_DEC + 0x8: mbox ++;
+ case AR6K_COUNT_DEC + 0x4: mbox ++;
+ case AR6K_COUNT_DEC + 0x0:
+ return s->hif.cnt_tx[mbox];
+
case AR6K_SCRATCH ... (AR6K_SCRATCH + 7):
return s->hif.scratch[addr - AR6K_SCRATCH];
+
case AR6K_FIFO_TIMEOUT:
case AR6K_FIFO_TIMEOUT_ENABLE:
case AR6K_DISABLE_SLEEP:
case AR6K_LOCAL_BUS_ENDIAN:
case AR6K_LOCAL_BUS:
+ goto bad_reg;
+
case AR6K_INT_WLAN:
+ return s->hif.wlan_int;
+
case AR6K_WINDOW_DATA:
case AR6K_WRITE_ADDR:
case AR6K_READ_ADDR:
@@ -1326,6 +1486,7 @@
struct sd_card_s *ret = sdio_init(&s->sd);
s->nd = nd;
+ s->cnt_irq_update = qemu_new_timer(vm_clock, ar6k_hif_cnt_irq_tick, s);
s->sd.reset = (void *) ar6k_reset;
s->sd.fbr[0].stdfn = 0 | sdio_fn_none;
s->sd.fbr[0].ext_stdfn = sdio_ext_fn_none;
--- End Message ---
--- Begin Message ---
Author: andrew
Date: 2007-12-29 03:11:33 +0100 (Sat, 29 Dec 2007)
New Revision: 3752
Modified:
trunk/src/host/qemu-neo1973/hw/ar6000.c
Log:
Add Atheros WMI events framework - we get a correct MAC addr now.
Modified: trunk/src/host/qemu-neo1973/hw/ar6000.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-28 20:50:54 UTC (rev
3751)
+++ trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-29 02:11:33 UTC (rev
3752)
@@ -1,5 +1,5 @@
/*
- * Atheros AR600X Wireless Ethernet SDIO cards. Firmware 1.3.
+ * ROCm Atheros AR600X Wireless Ethernet SDIO cards. Firmware 1.3.
*
* Copyright (c) 2007 OpenMoko, Inc.
* Author: Andrzej Zaborowski <[EMAIL PROTECTED]>
@@ -942,6 +942,115 @@
return &s->card;
}
+/* WMI (Wireless Module Interface) */
+
+struct wmi_s {
+ NICInfo *nd;
+
+ void (*send)(void *opaque, const uint8_t *buffer, int len);
+ void *opaque;
+
+ QEMUTimer *alive;
+};
+
+#define WMI_MSG __attribute__((packed))
+
+struct wmi_msg_s {
+ uint16_t id;
+ uint8_t data[128];
+} WMI_MSG;
+
+static void wmi_make_event(struct wmi_s *s, uint16_t id,
+ uint8_t *data, int len)
+{
+ struct wmi_msg_s msg;
+
+ msg.id = id;
+ memcpy(msg.data, data, len);
+
+ s->send(s->opaque, (void *) &msg, sizeof(msg.id) + len);
+}
+
+enum {
+ WMI_READY_EVENTID = 0x1001,
+ WMI_CONNECT_EVENTID,
+ WMI_DISCONNECT_EVENTID,
+ WMI_BSSINFO_EVENTID,
+ WMI_CMDERROR_EVENTID,
+ WMI_REGDOMAIN_EVENTID,
+ WMI_PSTREAM_TIMEOUT_EVENTID,
+ WMI_NEIGHBOR_REPORT_EVENTID,
+ WMI_TKIP_MICERR_EVENTID,
+ WMI_SCAN_COMPLETE_EVENTID,
+ WMI_REPORT_STATISTICS_EVENTID,
+ WMI_RSSI_THRESHOLD_EVENTID,
+ WMI_ERROR_REPORT_EVENTID,
+ WMI_OPT_RX_FRAME_EVENTID,
+ WMI_REPORT_ROAM_TBL_EVENTID,
+ WMI_EXTENSION_EVENTID,
+ WMI_CAC_EVENTID,
+ WMI_SNR_THRESHOLD_EVENTID,
+ WMI_LQ_THRESHOLD_EVENTID,
+ WMI_TX_RETRY_ERR_EVENTID,
+ WMI_REPORT_ROAM_DATA_EVENTID,
+};
+
+enum {
+ WMI_11A_CAPABILITY = 1,
+ WMI_11G_CAPABILITY = 2,
+ WMI_11AG_CAPABILITY = 3,
+};
+
+struct wmi_ready_event_s {
+ uint8_t macaddr[6];
+ uint8_t phy_capability;
+} WMI_MSG;
+
+static void wmi_ready_event(struct wmi_s *s)
+{
+ struct wmi_ready_event_s ev;
+
+ memcpy(ev.macaddr, s->nd->macaddr, 6);
+ ev.phy_capability = WMI_11AG_CAPABILITY;
+
+ /* TODO: request buf, fill in, submit */
+ wmi_make_event(s, WMI_READY_EVENTID, (void *) &ev, sizeof(ev));
+}
+
+/* The interface is alive */
+static void wmi_alive_tick(void *opaque)
+{
+ struct wmi_s *s = (void *) opaque;
+
+ qemu_free_timer(s->alive);
+
+ /* Send the initial event */
+ wmi_ready_event(s);
+}
+
+static __attribute__((malloc)) struct wmi_s *wmi_init(NICInfo *nd,
+ void *opaque,
+ void (*send)(void *opaque, const uint8_t *buffer, int len))
+{
+ struct wmi_s *s = qemu_mallocz(sizeof(*s));
+
+ s->nd = nd;
+ s->opaque = opaque;
+ s->send = send;
+
+ s->alive = qemu_new_timer(vm_clock, wmi_alive_tick, s);
+ qemu_mod_timer(s->alive, qemu_get_clock(vm_clock) + (ticks_per_sec << 1));
+
+ return s;
+}
+
+static void wmi_done(struct wmi_s *wmi)
+{
+ free(wmi);
+}
+
+/* Atheros AR600x */
+
struct ar6k_s {
struct sdio_s sd;
NICInfo *nd;
@@ -953,7 +1062,7 @@
uint8_t counter_int_stat;
uint8_t mbox_frame;
uint8_t rx_la_valid;
- uint8_t rx_la[4];
+ uint32_t rx_la[4];
uint8_t int_stat_ena;
uint8_t cpu_int_stat_ena;
uint8_t err_int_stat_ena;
@@ -970,6 +1079,8 @@
int done;
} bmi;
+ struct wmi_s *wmi;
+
QEMUTimer *cnt_irq_update;
uint8_t cis[0];
@@ -1033,10 +1144,17 @@
ar6k_hif_counter_intr_update(s);
}
+/* Atheros BMI (Bootloader Messaging Interface) */
+
static void ar6k_bmi_reset(struct ar6k_s *s)
{
int i;
+ if (s->wmi) {
+ wmi_done(s->wmi);
+ s->wmi = 0;
+ }
+
for (i = 0; i < 4; i ++) {
s->hif.cnt[i] = 0x00;
s->hif.cnt_tx[i] = 0xff;
@@ -1122,6 +1240,15 @@
s->hif.cnt[0] = rlen;
}
+/* Atheros HTC/HIF */
+
+enum {
+ WMI_CONTROL_MBOX = 0,
+ WMI_BEST_EFFORT_MBOX,
+ WMI_LOW_PRIORITY_MBOX,
+ WMI_HIGH_PRIORITY_MBOX,
+};
+
static void ar6k_hif_txcredit_reset(struct ar6k_s *s, int mbox)
{
s->hif.cnt_tx[mbox] = 0;
@@ -1140,6 +1267,33 @@
}
}
+#define AR6K_HTC_HEADER_LEN 2
+
+static void ar6k_hif_wmi_event(void *opaque, const uint8_t *buffer, int len)
+{
+ struct ar6k_s *s = (void *) opaque;
+
+ int mbox = WMI_CONTROL_MBOX;
+ uint16_t *datap;
+
+ s->hif.rx_la[mbox] = len;
+ s->hif.rx_la_valid |= 1 << mbox;
+
+ datap = (void *) s->hif.mbox + ((mbox + 1) << 11) -
+ (len + AR6K_HTC_HEADER_LEN);
+
+ /* Prepend the HTC frame header */
+ cpu_to_le16wu(datap ++, len);
+
+ memcpy(datap, buffer, len);
+
+ if (!(s->hif.host_int_stat & (1 << mbox))) { /* STATUS_MBOX_DATA */
+ s->hif.host_int_stat |= 1 << mbox; /* STATUS_MBOX_DATA */
+
+ ar6k_hif_intr_update(s);
+ }
+}
+
#define AR6K_HOST_INT_STAT 0x400
#define AR6K_CPU_INT_STAT 0x401
#define AR6K_ERROR_INT_STAT 0x402
@@ -1206,24 +1360,11 @@
ar6k_hif_counter_intr_update(s);
}
break;
+
case AR6K_MBOX_FRAME:
s->hif.mbox_frame = value;
break;
- case AR6K_RX_LOOKAHEAD_VALID:
- s->hif.rx_la_valid = value;
- break;
- case AR6K_RX_LOOKAHEAD0:
- s->hif.rx_la[0] = value;
- break;
- case AR6K_RX_LOOKAHEAD1:
- s->hif.rx_la[1] = value;
- break;
- case AR6K_RX_LOOKAHEAD2:
- s->hif.rx_la[2] = value;
- break;
- case AR6K_RX_LOOKAHEAD3:
- s->hif.rx_la[3] = value;
- break;
+
case AR6K_INT_STAT_ENABLE:
if (s->hif.int_stat_ena ^ value) {
s->hif.int_stat_ena = value;
@@ -1248,9 +1389,11 @@
ar6k_hif_counter_intr_sched(s);
}
break;
+
case AR6K_SCRATCH ... (AR6K_SCRATCH + 7):
s->hif.scratch[addr - AR6K_SCRATCH] = value;
break;
+
case AR6K_FIFO_TIMEOUT:
case AR6K_FIFO_TIMEOUT_ENABLE:
case AR6K_DISABLE_SLEEP:
@@ -1260,8 +1403,10 @@
case AR6K_INT_WLAN:
s->hif.wlan_int = value;
- if (value)
- fprintf(stderr, "%s: WLAN interrupt\n", __FUNCTION__);
+ if (value && !s->wmi) {
+ /* Initialisation sequence is complete (?). */
+ s->wmi = wmi_init(s->nd, s, ar6k_hif_wmi_event);
+ }
break;
case AR6K_WINDOW_DATA:
@@ -1313,15 +1458,18 @@
case AR6K_RX_LOOKAHEAD_VALID:
return s->hif.rx_la_valid;
- case AR6K_RX_LOOKAHEAD0:
- return s->hif.rx_la[0];
- case AR6K_RX_LOOKAHEAD1:
- return s->hif.rx_la[1];
- case AR6K_RX_LOOKAHEAD2:
- return s->hif.rx_la[2];
- case AR6K_RX_LOOKAHEAD3:
- return s->hif.rx_la[3];
+ case AR6K_RX_LOOKAHEAD3 ... (AR6K_RX_LOOKAHEAD3 + 3): mbox ++;
+ case AR6K_RX_LOOKAHEAD2 ... (AR6K_RX_LOOKAHEAD2 + 3): mbox ++;
+ case AR6K_RX_LOOKAHEAD1 ... (AR6K_RX_LOOKAHEAD1 + 3): mbox ++;
+ case AR6K_RX_LOOKAHEAD0 ... (AR6K_RX_LOOKAHEAD0 + 3):
+ /* XXX when is the bit reset? */
+ s->hif.rx_la_valid &= ~(1 << mbox);
+ /* XXX when is the bit reset? */
+ s->hif.host_int_stat &= ~(1 << mbox); /* STATUS_MBOX_DATA */
+ ar6k_hif_intr_update(s);
+ return (s->hif.rx_la[mbox] >> ((addr & 3) << 3)) & 0xff;
+
case AR6K_INT_STAT_ENABLE:
return s->hif.int_stat_ena;
case AR6K_CPU_INT_STAT_ENABLE:
@@ -1394,7 +1542,6 @@
{
struct ar6k_s *s = (void *) sd;
- fprintf(stderr, "%s: writing %i bytes at %x\n", __FUNCTION__, len, addr);
for (; len; len --, addr += sd->transfer.step)
ar6k_hif_write(s, addr, *data ++);
}
@@ -1404,7 +1551,6 @@
{
struct ar6k_s *s = (void *) sd;
- fprintf(stderr, "%s: reading %i bytes at %x\n", __FUNCTION__, len, addr);
for (; len; len --, addr += sd->transfer.step)
*data ++ = ar6k_hif_read(s, addr);
}
--- End Message ---
--- Begin Message ---
Author: andrew
Date: 2007-12-29 03:55:56 +0100 (Sat, 29 Dec 2007)
New Revision: 3753
Modified:
trunk/src/host/qemu-neo1973/hw/ar6000.c
trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c
Log:
Teach CMD52 to preserve concurrently executing transfers.
Fix commands without data in S3C24xx mmc/sd host.
Decrement tx-credits on COUNTER_DEC read.
Modified: trunk/src/host/qemu-neo1973/hw/ar6000.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-29 02:11:33 UTC (rev
3752)
+++ trunk/src/host/qemu-neo1973/hw/ar6000.c 2007-12-29 02:55:56 UTC (rev
3753)
@@ -76,6 +76,7 @@
int spi;
int sdio_ok;
int current_cmd;
+ int next_cmd;
uint16_t blk_len[8];
struct {
uint8_t func;
@@ -370,10 +371,13 @@
/* I/O mode commands (Class 9) */
case 52: /* CMD52: IO_RW_DIRECT */
- /* XXX In some situations this must preserve cmdNo and restore later */
switch (sd->state) {
+ case sd_transfer_state:
+ /* A transfer is active on DAT lines, don't break it. */
+ sd->next_cmd = sd->current_cmd;
+
+ /* Fall through. */
case sd_command_state:
- case sd_transfer_state:
fun = (req.arg >> 28) & 7;
addr = (req.arg >> 9) & SDIO_ADDR_MASK;
sd->transfer.data_offset = 0;
@@ -475,9 +479,10 @@
sd->card_status &= ~(COM_CRC_ERROR | ILLEGAL_COMMAND); /* B type */
+ sd->next_cmd = req->cmd;
rtype = sdio_normal_command(sd, *req);
- sd->current_cmd = req->cmd;
+ sd->current_cmd = sd->next_cmd;
switch (rtype) {
case sd_r1:
@@ -699,10 +704,11 @@
return sd->cccr.bus;
case 0x08: /* Card Capability */
- /* XXX: set SDC (01) when CMD52 learns to preserve current_cmd */
- /* XXX: need to addr ReadWait support too (RWC (04)) */
- return 0x12 | sd->cccr.e4mi; /* SMB | S4MI | E4MI | Full-Speed */
+ /* XXX: need to add ReadWait support too (RWC (04)) */
+ /* SDC | SMB | S4MI | E4MI | Full-Speed */
+ return 0x13 | sd->cccr.e4mi;
+
case 0x09: /* Common CIS Pointer */
return (SDIO_CIS_START >> 0) & 0xff;
case 0x0a: /* Common CIS Pointer */
@@ -1022,6 +1028,8 @@
{
struct wmi_s *s = (void *) opaque;
+ /* TODO: reschedule if we're in the middle of a transfer or other
+ * activity. Do the same for other timers we may need in WMI. */
qemu_free_timer(s->alive);
/* Send the initial event */
@@ -1498,7 +1506,7 @@
case AR6K_COUNT_DEC + 0x8: mbox ++;
case AR6K_COUNT_DEC + 0x4: mbox ++;
case AR6K_COUNT_DEC + 0x0:
- return s->hif.cnt_tx[mbox];
+ return s->hif.cnt_tx[mbox] --;
case AR6K_SCRATCH ... (AR6K_SCRATCH + 7):
return s->hif.scratch[addr - AR6K_SCRATCH];
Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c 2007-12-29 02:11:33 UTC
(rev 3752)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c 2007-12-29 02:55:56 UTC
(rev 3753)
@@ -170,6 +170,7 @@
s->blklen_cnt = s->blklen;
s->blknum_cnt = s->blknum;
+ s->data = 0;
if (((s->dcontrol >> 12) & 3) == 1) { /* DatMode */
if (s->dcontrol & (1 << 18)) /* BACMD */
s->data = 1;
@@ -179,6 +180,7 @@
} else if (((s->dcontrol >> 12) & 3) == 3) /* DatMode */
if (s->dcontrol & (1 << 20)) /* RACMD */
s->data = 1;
+ s->data &= s->ccontrol >> 11; /* WithData */
return;
timeout:
--- End Message ---
_______________________________________________
commitlog mailing list
[email protected]
http://lists.openmoko.org/mailman/listinfo/commitlog