iio: imu: nvi v.333 ICM DMP FW v.2
Erik Lilliebjerg [Wed, 29 Jun 2016 01:57:07 +0000 (18:57 -0700)]
- Implement Invensense ICM DMP FW v.2 that fixes sensor data timing gaps.

Bug 1768847

Change-Id: I0bde444d2cdfa0721541fad40589135a37a74acd
Signed-off-by: Erik Lilliebjerg <elilliebjerg@nvidia.com>
Reviewed-on: http://git-master/r/1172879
(cherry picked from commit c95d320e9a4b85d13261d2572a39608e1dbb5f43)
Reviewed-on: http://git-master/r/1185051
GVS: Gerrit_Virtual_Submit
Tested-by: Robert Collins <rcollins@nvidia.com>
Reviewed-by: Robert Collins <rcollins@nvidia.com>

drivers/iio/imu/nvi_mpu/nvi.c
drivers/iio/imu/nvi_mpu/nvi.h
drivers/iio/imu/nvi_mpu/nvi_dmp_icm.c
drivers/iio/imu/nvi_mpu/nvi_dmp_icm.h
drivers/iio/imu/nvi_mpu/nvi_icm.c

index 1efe07a..c5ed766 100644 (file)
@@ -29,7 +29,7 @@
 
 #include "nvi.h"
 
-#define NVI_DRIVER_VERSION             (330)
+#define NVI_DRIVER_VERSION             (333)
 #define NVI_VENDOR                     "Invensense"
 #define NVI_NAME                       "mpu6xxx"
 #define NVI_NAME_MPU6050               "mpu6050"
@@ -106,7 +106,8 @@ enum NVI_INFO {
        NVI_INFO_MEM_RD,
        NVI_INFO_MEM_WR,
        NVI_INFO_DMP_FW,
-       NVI_INFO_DMP_EN_MSK
+       NVI_INFO_DMP_EN_MSK,
+       NVI_INFO_FN_INIT
 };
 
 /* regulator names in order of powering on */
@@ -206,6 +207,16 @@ static void nvi_enable_irq(struct nvi_state *st)
        }
 }
 
+static void nvi_rc_clr(struct nvi_state *st, const char *fn)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(st->rc_msk); i++)
+               st->rc_msk[i] = 0;
+       if (st->sts & NVI_DBG_SPEW_MSG)
+               dev_info(&st->i2c->dev, "%s-%s\n", __func__, fn);
+}
+
 static int nvi_i2c_w(struct nvi_state *st, u16 len, u8 *buf)
 {
        struct i2c_msg msg;
@@ -225,24 +236,33 @@ static int nvi_i2c_w(struct nvi_state *st, u16 len, u8 *buf)
 static int nvi_wr_reg_bank_sel(struct nvi_state *st, u8 reg_bank)
 {
        u8 buf[2];
+       bool wr = true;
        int ret = 0;
 
        if (!st->hal->reg->reg_bank.reg)
                return 0;
 
        reg_bank <<= 4;
-       if (reg_bank != st->rc.reg_bank) {
+       if (st->rc_msk[NVI_RC_BANK_REG_BANK] & NVI_RC_MSK_REG_BANK) {
+               if (reg_bank == st->rc.reg_bank)
+                       wr = false;
+       }
+       if (wr) {
                buf[0] = st->hal->reg->reg_bank.reg;
                buf[1] = reg_bank;
                ret = nvi_i2c_w(st, sizeof(buf), buf);
                if (ret) {
                        dev_err(&st->i2c->dev, "%s 0x%x!->0x%x ERR=%d\n",
                                __func__, st->rc.reg_bank, reg_bank, ret);
+                       st->rc_msk[NVI_RC_BANK_REG_BANK] &=
+                                                         ~NVI_RC_MSK_REG_BANK;
                } else {
                        if (st->sts & NVI_DBG_SPEW_MSG)
                                dev_info(&st->i2c->dev, "%s 0x%x->0x%x\n",
                                         __func__, st->rc.reg_bank, reg_bank);
                        st->rc.reg_bank = reg_bank;
+                       st->rc_msk[NVI_RC_BANK_REG_BANK] |=
+                                                          NVI_RC_MSK_REG_BANK;
                }
        }
        return ret;
@@ -285,26 +305,44 @@ static int nvi_i2c_write_le(struct nvi_state *st, const struct nvi_br *br,
 int nvi_i2c_write_rc(struct nvi_state *st, const struct nvi_br *br, u32 val,
                     const char *fn, u8 *rc, bool be)
 {
-       bool wr = false;
        u16 len;
+       u64 rc_msk;
+       bool wr;
+       unsigned int rc_bank;
        unsigned int i;
        int ret = 0;
 
        len = br->len;
        if (!len)
                len++;
+       rc_bank = br->bank;
+       rc_bank <<= 7; /* registers only go to 0x7F */
+       rc_bank |= br->reg;
+       rc_msk = ((1 << len) - 1) << (rc_bank % 64);
+       rc_bank /= 64;
        val |= br->dflt;
-       if (rc != NULL) {
-               for (i = 0; i < len; i++) {
-                       if (*(rc + i) != (u8)(val >> (8 * i))) {
+       wr = st->rc_dis;
+       if (!wr) {
+               if (rc) {
+                       if ((st->rc_msk[rc_bank] & rc_msk) == rc_msk) {
+                               /* register is cached */
+                               for (i = 0; i < len; i++) {
+                                       if (*(rc + i) !=
+                                                       (u8)(val >> (8 * i))) {
+                                               /* register data changed */
+                                               wr = true;
+                                               break;
+                                       }
+                               }
+                       } else {
+                               /* register not cached */
                                wr = true;
-                               break;
                        }
+               } else {
+                       wr = true;
                }
-       } else {
-               wr = true;
        }
-       if (wr || st->rc_dis) {
+       if (wr) {
                if (be)
                        ret = nvi_i2c_write_be(st, br, len, val);
                else
@@ -315,14 +353,19 @@ int nvi_i2c_write_rc(struct nvi_state *st, const struct nvi_br *br, u32 val,
                        dev_err(&st->i2c->dev,
                                "%s 0x%08x!=>0x%01x%02x ERR=%d\n",
                                fn, val, br->bank, br->reg, ret);
+                       st->rc_msk[rc_bank] &= ~rc_msk;
                } else {
                        if (st->sts & NVI_DBG_SPEW_MSG && fn)
                                dev_info(&st->i2c->dev,
                                         "%s 0x%08x=>0x%01x%02x\n",
                                         fn, val, br->bank, br->reg);
-                       if (rc != NULL) {
+                       if (rc) {
                                for (i = 0; i < len; i++)
                                        *(rc + i) = (u8)(val >> (8 * i));
+                               st->rc_msk[rc_bank] |= rc_msk;
+                       } else {
+                               /* register data not cached */
+                               st->rc_msk[rc_bank] &= ~rc_msk;
                        }
                }
        }
@@ -359,13 +402,45 @@ int nvi_i2c_wr(struct nvi_state *st, const struct nvi_br *br,
 int nvi_i2c_wr_rc(struct nvi_state *st, const struct nvi_br *br,
                  u8 val, const char *fn, u8 *rc)
 {
+       u64 rc_msk;
+       bool wr;
+       unsigned int rc_bank;
        int ret = 0;
 
        val |= br->dflt;
-       if (val != *rc || st->rc_dis) {
+       rc_bank = br->bank;
+       rc_bank <<= 7; /* registers only go to 0x7F */
+       rc_bank |= br->reg;
+       rc_msk = 1 << (rc_bank % 64);
+       rc_bank /= 64;
+       wr = st->rc_dis;
+       if (!wr) {
+               if (rc) {
+                       if (st->rc_msk[rc_bank] & rc_msk) {
+                               /* register is cached */
+                               if (val != *rc)
+                                       /* register data changed */
+                                       wr = true;
+                       } else {
+                               /* register not cached */
+                               wr = true;
+                       }
+               } else {
+                       wr = true;
+               }
+       }
+       if (wr) {
                ret = nvi_i2c_wr(st, br, val, fn);
-               if (!ret)
-                       *rc = val;
+               if (ret) {
+                       st->rc_msk[rc_bank] &= ~rc_msk;
+               } else {
+                       if (rc) {
+                               *rc = val;
+                               st->rc_msk[rc_bank] |= rc_msk;
+                       } else {
+                               st->rc_msk[rc_bank] &= ~rc_msk;
+                       }
+               }
        }
        return ret;
 }
@@ -775,7 +850,8 @@ static int nvi_user_ctrl_rst(struct nvi_state *st, u8 user_ctrl)
                if (st->hal->reg->fifo_rst.reg) {
                        /* ICM part */
                        if (st->en_msk & (1 << DEV_DMP)) {
-                               ret = nvi_wr_fifo_cfg(st, 0);
+                               ret = nvi_wr_fifo_cfg(st,
+                                                     st->hal->dmp->fifo_mode);
                        } else {
                                n = 0;
                                for (i = 0; i < DEV_AXIS_N; i++) {
@@ -933,9 +1009,8 @@ int nvi_wr_pm1(struct nvi_state *st, const char *fn, u8 pm1)
        st->pm = NVI_PM_ERR;
        if (pm1 & BIT_H_RESET && !ret) {
                st->en_msk &= MSK_RST;
-               memset(&st->rc, 0, sizeof(st->rc));
-               if (st->hal->fn->por2rc)
-                       st->hal->fn->por2rc(st);
+               nvi_rc_clr(st, __func__);
+               st->rc_dis = false;
                for (i = 0; i < st->hal->src_n; i++)
                        st->src[i].period_us_req = 0;
 
@@ -948,11 +1023,9 @@ int nvi_wr_pm1(struct nvi_state *st, const char *fn, u8 pm1)
                }
 
                msleep(POR_MS);
-               st->rc.pm1 = pm1_rd;
                nvi_rd_accel_offset(st);
                nvi_rd_gyro_offset(st);
                nvi_dmp_fw(st);
-               st->rc_dis = false;
        }
        if (st->sts & NVI_DBG_SPEW_MSG)
                dev_info(&st->i2c->dev, "%s-%s pm1=%x err=%d\n",
@@ -1177,6 +1250,7 @@ static int nvi_dmp_fw(struct nvi_state *st)
 #endif /* NVI_FW_CRC_CHECK */
        int ret;
 
+       st->icm_dmp_war = false;
        if (!st->hal->dmp)
                return -EINVAL;
 
@@ -1417,7 +1491,11 @@ static int nvi_en(struct nvi_state *st)
                if (i < DEV_N_AUX)
                        break;
 
-               return nvi_pm(st, __func__, NVI_PM_AUTO);
+               ret_t = nvi_pm(st, __func__, NVI_PM_AUTO);
+               if (st->sts & (NVS_STS_SPEW_MSG | NVI_DBG_SPEW_MSG))
+                       dev_info(&st->i2c->dev, "%s en_msk=%x err=%d\n",
+                                __func__, st->en_msk, ret_t);
+               return ret_t;
        }
 
        ret_t |= nvi_int_able(st, __func__, false);
@@ -1843,7 +1921,8 @@ static int nvi_aux_bypass_request(struct nvi_state *st, bool enable)
        } else {
                if (st->aux.bypass_lock) {
                        ns = nvs_timestamp() - st->aux.bypass_timeout_ns;
-                       to = st->bypass_timeout_ms * 1000000;
+                       to = st->bypass_timeout_ms;
+                       to *= 1000000;
                        if (ns > to)
                                st->aux.bypass_lock = 0;
                        else
@@ -2775,7 +2854,8 @@ static int nvi_fifo_rd(struct nvi_state *st, int src, unsigned int fifo_n_max,
        }
 
        if (ts_n) {
-               ts_period = st->src[src].period_us_src * 1000;
+               ts_period = st->src[src].period_us_src;
+               ts_period *= 1000;
                if (sync && ts_end > st->src[src].ts_end && ts_end < ts_now &&
                                          ts_end > (ts_now - (ts_period >> 2)))
                        /* ts_irq is within the rate so sync to IRQ */
@@ -3092,6 +3172,7 @@ static int nvi_flush(void *client, int snsr_id)
 static int nvi_max_range(void *client, int snsr_id, int max_range)
 {
        struct nvi_state *st = (struct nvi_state *)client;
+       int ret = 0;
        unsigned int i = max_range;
        unsigned int ch;
 
@@ -3128,7 +3209,9 @@ static int nvi_max_range(void *client, int snsr_id, int max_range)
                }
        }
 
-       return 0;
+       if (st->en_msk & (1 << DEV_DMP))
+               ret = nvi_en(st);
+       return ret;
 }
 
 static int nvi_offset(void *client, int snsr_id, int channel, int offset)
@@ -3231,9 +3314,9 @@ static int nvi_self_test(void *client, int snsr_id, char *buf)
        nvi_period_all(st);
        nvi_en(st);
        if (ret)
-               return sprintf(buf, "%d   FAIL\n", ret);
+               return snprintf(buf, PAGE_SIZE, "%d   FAIL\n", ret);
 
-       return sprintf(buf, "%d   PASS\n", ret);
+       return snprintf(buf, PAGE_SIZE, "%d   PASS\n", ret);
 }
 
 static int nvi_regs(void *client, int snsr_id, char *buf)
@@ -3245,9 +3328,9 @@ static int nvi_regs(void *client, int snsr_id, char *buf)
        unsigned int j;
        int ret;
 
-       t = sprintf(buf, "registers: (only data != 0 shown)\n");
+       t = snprintf(buf, PAGE_SIZE, "registers: (only data != 0 shown)\n");
        for (j = 0; j < st->hal->reg_bank_n; j++) {
-               t += sprintf(buf + t, "bank %u:\n", j);
+               t += snprintf(buf + t, PAGE_SIZE - t, "bank %u:\n", j);
                for (i = 0; i < st->hal->regs_n; i++) {
                        if ((j == st->hal->reg->fifo_rw.bank) &&
                                              (i == st->hal->reg->fifo_rw.reg))
@@ -3255,9 +3338,10 @@ static int nvi_regs(void *client, int snsr_id, char *buf)
 
                        ret = nvi_i2c_r(st, j, i, 1, &data);
                        if (ret)
-                               t += sprintf(buf + t, "0x%02x=ERR\n", i);
+                               t += snprintf(buf + t, PAGE_SIZE - t,
+                                             "0x%02x=ERR\n", i);
                        else if (data)
-                               t += sprintf(buf + t,
+                               t += snprintf(buf + t, PAGE_SIZE - t,
                                             "0x%02x=0x%02x\n", i, data);
                }
        }
@@ -3276,6 +3360,7 @@ static int nvi_nvs_write(void *client, int snsr_id, unsigned int nvs)
        case NVI_INFO_MEM_WR:
        case NVI_INFO_DMP_FW:
        case NVI_INFO_DMP_EN_MSK:
+       case NVI_INFO_FN_INIT:
                break;
 
        case NVI_INFO_DBG_SPEW:
@@ -3321,75 +3406,85 @@ static int nvi_nvs_read(void *client, int snsr_id, char *buf)
        st->info = NVI_INFO_VER;
        switch (info & 0xFF) {
        case NVI_INFO_VER:
-               t = sprintf(buf, "NVI driver v. %u\n", NVI_DRIVER_VERSION);
+               t = snprintf(buf, PAGE_SIZE, "NVI driver v. %u\n",
+                            NVI_DRIVER_VERSION);
                if (st->en_msk & (1 << FW_LOADED)) {
-                       t += sprintf(buf + t, "DMP FW v. %u\n",
-                                    st->hal->dmp->fw_ver);
-                       t += sprintf(buf + t, "DMP enabled=%u\n",
-                                    !!(st->en_msk & (1 << DEV_DMP)));
+                       t += snprintf(buf + t, PAGE_SIZE - t, "DMP FW v. %u\n",
+                                     st->hal->dmp->fw_ver);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "DMP enabled=%u\n",
+                                     !!(st->en_msk & (1 << DEV_DMP)));
                }
-               t += sprintf(buf + t, "standby_en=%x\n",
-                            !!(st->en_msk & (1 << EN_STDBY)));
-               t += sprintf(buf + t, "bypass_timeout_ms=%u\n",
-                            st->bypass_timeout_ms);
+               t += snprintf(buf + t, PAGE_SIZE - t, "standby_en=%x\n",
+                             !!(st->en_msk & (1 << EN_STDBY)));
+               t += snprintf(buf + t, PAGE_SIZE - t, "bypass_timeout_ms=%u\n",
+                             st->bypass_timeout_ms);
                for (i = 0; i < DEV_N_AUX; i++) {
                        if (st->snsr[i].push_delay_ns)
-                               t += sprintf(buf + t,
-                                            "%s_push_delay_ns=%lld\n",
-                                            st->snsr[i].cfg.name,
-                                            st->snsr[i].push_delay_ns);
+                               t += snprintf(buf + t, PAGE_SIZE - t,
+                                             "%s_push_delay_ns=%lld\n",
+                                             st->snsr[i].cfg.name,
+                                             st->snsr[i].push_delay_ns);
                }
 
                for (i = 0; i < DEV_N_AUX; i++) {
                        if ((st->dmp_dev_msk | MSK_DEV_MPU_AUX) & (1 << i)) {
                                if (st->dmp_en_msk & (1 << i))
-                                       t += sprintf(buf + t, "%s_dmp_en=1\n",
-                                                    st->snsr[i].cfg.name);
+                                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                                     "%s_dmp_en=1\n",
+                                                     st->snsr[i].cfg.name);
                                else
-                                       t += sprintf(buf + t, "%s_dmp_en=0\n",
-                                                    st->snsr[i].cfg.name);
+                                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                                     "%s_dmp_en=0\n",
+                                                     st->snsr[i].cfg.name);
                        }
                }
 
                return t;
 
        case NVI_INFO_DBG:
-               t = sprintf(buf, "en_msk=%x\n", st->en_msk);
-               t += sprintf(buf + t, "sts=%x\n", st->sts);
-               t += sprintf(buf + t, "pm=%d\n", st->pm);
-               t += sprintf(buf + t, "bm_timeout_us=%u\n", st->bm_timeout_us);
-               t += sprintf(buf + t, "fifo_src=%d\n", st->fifo_src);
+               t = snprintf(buf, PAGE_SIZE, "en_msk=%x\n", st->en_msk);
+               t += snprintf(buf + t, PAGE_SIZE - t, "sts=%x\n", st->sts);
+               t += snprintf(buf + t, PAGE_SIZE - t, "pm=%d\n", st->pm);
+               t += snprintf(buf + t, PAGE_SIZE - t, "bm_timeout_us=%u\n",
+                             st->bm_timeout_us);
+               t += snprintf(buf + t, PAGE_SIZE - t, "fifo_src=%d\n",
+                             st->fifo_src);
                for (i = 0; i < DEV_N_AUX; i++) {
-                       t += sprintf(buf + t, "snsr[%u] %s:\n",
-                                    i, st->snsr[i].cfg.name);
-                       t += sprintf(buf + t, "enable=%x\n",
-                                    st->snsr[i].enable);
-                       t += sprintf(buf + t, "period_us=%u\n",
-                                    st->snsr[i].period_us);
-                       t += sprintf(buf + t, "timeout_us=%u\n",
-                                    st->snsr[i].timeout_us);
-                       t += sprintf(buf + t, "odr=%u\n",
-                                    st->snsr[i].odr);
-                       t += sprintf(buf + t, "ts_last=%lld\n",
-                                    st->snsr[i].ts_last);
-                       t += sprintf(buf + t, "ts_reset=%x\n",
-                                    st->snsr[i].ts_reset);
-                       t += sprintf(buf + t, "flush=%x\n",
-                                    st->snsr[i].flush);
-                       t += sprintf(buf + t, "matrix=%x\n",
-                                    st->snsr[i].matrix);
-                       t += sprintf(buf + t, "buf_shft=%d\n",
-                                    st->snsr[i].buf_shft);
-                       t += sprintf(buf + t, "buf_n=%u\n",
-                                    st->snsr[i].buf_n);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "snsr[%u] %s:\n",
+                                     i, st->snsr[i].cfg.name);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "usr_cfg=%x\n",
+                                     st->snsr[i].usr_cfg);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "enable=%x\n",
+                                     st->snsr[i].enable);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "period_us=%u\n",
+                                     st->snsr[i].period_us);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "timeout_us=%u\n",
+                                     st->snsr[i].timeout_us);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "odr=%u\n",
+                                     st->snsr[i].odr);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "ts_last=%lld\n",
+                                     st->snsr[i].ts_last);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "ts_reset=%x\n",
+                                     st->snsr[i].ts_reset);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "flush=%x\n",
+                                     st->snsr[i].flush);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "matrix=%x\n",
+                                     st->snsr[i].matrix);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "buf_shft=%d\n",
+                                     st->snsr[i].buf_shft);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "buf_n=%u\n",
+                                     st->snsr[i].buf_n);
                }
 
                if (st->hal->dmp) {
                        /* nvi_dmp_clk_n */
                        st->hal->dmp->fn_clk_n(st, &n);
-                       t += sprintf(buf + t, "nvi_dmp_clk_n=%u\n", n);
-                       t += sprintf(buf + t, "st->dmp_clk_n=%u\n",
-                                    st->dmp_clk_n);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "nvi_dmp_clk_n=%u\n", n);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "st->dmp_clk_n=%u\n", st->dmp_clk_n);
                        n = SRC_DMP;
                } else {
                        n = 0;
@@ -3398,47 +3493,58 @@ static int nvi_nvs_read(void *client, int snsr_id, char *buf)
                        if (i >= st->hal->src_n && i != SRC_DMP)
                                continue;
 
-                       t += sprintf(buf + t, "src[%u]:\n", i);
-                       t += sprintf(buf + t, "ts_reset=%x\n",
-                                    st->src[i].ts_reset);
-                       t += sprintf(buf + t, "ts_end=%lld\n",
-                                    st->src[i].ts_end);
-                       t += sprintf(buf + t, "ts_period=%lld\n",
-                                    st->src[i].ts_period);
-                       t += sprintf(buf + t, "period_us_src=%u\n",
-                                    st->src[i].period_us_src);
-                       t += sprintf(buf + t, "period_us_req=%u\n",
-                                    st->src[i].period_us_req);
-                       t += sprintf(buf + t, "fifo_data_n=%u\n",
-                                    st->src[i].fifo_data_n);
-                       t += sprintf(buf + t, "base_t=%u\n",
-                                    st->src[i].base_t);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "src[%u]:\n", i);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "ts_reset=%x\n",
+                                     st->src[i].ts_reset);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "ts_end=%lld\n",
+                                     st->src[i].ts_end);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "ts_period=%lld\n",
+                                     st->src[i].ts_period);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "period_us_src=%u\n",
+                                     st->src[i].period_us_src);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "period_us_req=%u\n",
+                                     st->src[i].period_us_req);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "period_us_min=%u\n",
+                                     st->src[i].period_us_min);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "period_us_max=%u\n",
+                                     st->src[i].period_us_max);
+                       t += snprintf(buf + t, PAGE_SIZE - t,
+                                     "fifo_data_n=%u\n",
+                                     st->src[i].fifo_data_n);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "base_t=%u\n",
+                                     st->src[i].base_t);
                }
                return t;
 
        case NVI_INFO_DBG_SPEW:
-               return sprintf(buf, "DBG spew=%x\n",
-                              !!(st->sts & NVI_DBG_SPEW_MSG));
+               return snprintf(buf, PAGE_SIZE, "DBG spew=%x\n",
+                               !!(st->sts & NVI_DBG_SPEW_MSG));
 
        case NVI_INFO_AUX_SPEW:
-               return sprintf(buf, "AUX spew=%x\n",
-                              !!(st->sts & NVI_DBG_SPEW_AUX));
+               return snprintf(buf, PAGE_SIZE, "AUX spew=%x\n",
+                               !!(st->sts & NVI_DBG_SPEW_AUX));
 
        case NVI_INFO_FIFO_SPEW:
-               return sprintf(buf, "FIFO spew=%x\n",
-                              !!(st->sts & NVI_DBG_SPEW_FIFO));
+               return snprintf(buf, PAGE_SIZE, "FIFO spew=%x\n",
+                               !!(st->sts & NVI_DBG_SPEW_FIFO));
 
        case NVI_INFO_TS_SPEW:
-               return sprintf(buf, "TS spew=%x\n",
-                              !!(st->sts & NVI_DBG_SPEW_TS));
+               return snprintf(buf, PAGE_SIZE, "TS spew=%x\n",
+                               !!(st->sts & NVI_DBG_SPEW_TS));
 
        case NVI_INFO_REG_WR:
                st->rc_dis = true;
                buf_rw[0] = (u8)(info >> 16);
                buf_rw[1] = (u8)(info >> 8);
                ret = nvi_i2c_write(st, info >> 24, 2, buf_rw);
-               return sprintf(buf, "REG WR: b=%02x r=%02x d=%02x ERR=%d\n",
-                              info >> 24, buf_rw[0], buf_rw[1], ret);
+               return snprintf(buf, PAGE_SIZE,
+                               "REG WR: b=%02x r=%02x d=%02x ERR=%d\n",
+                               info >> 24, buf_rw[0], buf_rw[1], ret);
 
        case NVI_INFO_MEM_RD:
                n = (info >> 8) & 0xFF;
@@ -3446,40 +3552,54 @@ static int nvi_nvs_read(void *client, int snsr_id, char *buf)
                        n = sizeof(buf_rw);
                ret = nvi_mem_rd(st, info >> 16, n, buf_rw);
                if (ret)
-                       return sprintf(buf, "MEM RD: ERR=%d\n", ret);
+                       return snprintf(buf, PAGE_SIZE,
+                                       "MEM RD: ERR=%d\n", ret);
 
-               t = sprintf(buf, "MEM RD:\n");
+               t = snprintf(buf, PAGE_SIZE, "MEM RD:\n");
                for (i = 0; i < n; i++) {
                        if (!(i % 8))
-                               t += sprintf(buf + t, "%04x: ",
-                                            (info >> 16) + i);
-                       t += sprintf(buf + t, "%02x ", buf_rw[i]);
+                               t += snprintf(buf + t, PAGE_SIZE - t, "%04x: ",
+                                             (info >> 16) + i);
+                       t += snprintf(buf + t, PAGE_SIZE - t, "%02x ",
+                                     buf_rw[i]);
                        if (!((i + 1) % 8))
-                               t += sprintf(buf + t, "\n");
+                               t += snprintf(buf + t, PAGE_SIZE - t, "\n");
                }
-               t += sprintf(buf + t, "\n");
+               t += snprintf(buf + t, PAGE_SIZE - t, "\n");
                return t;
 
        case NVI_INFO_MEM_WR:
                st->mc_dis = true;
                buf_rw[0] = (u8)(info >> 8);
                ret = nvi_mem_wr(st, info >> 16, 1, buf_rw, true);
-               return sprintf(buf, "MEM WR: a=%04x d=%02x ERR=%d\n",
-                              info >> 16, buf_rw[0], ret);
+               return snprintf(buf, PAGE_SIZE,
+                               "MEM WR: a=%04x d=%02x ERR=%d\n",
+                               info >> 16, buf_rw[0], ret);
 
        case NVI_INFO_DMP_FW:
                ret = nvi_dmp_fw(st);
-               return sprintf(buf, "DMP FW: ERR=%d\n", ret);
+               return snprintf(buf, PAGE_SIZE, "DMP FW: ERR=%d\n", ret);
 
        case NVI_INFO_DMP_EN_MSK:
                st->dmp_en_msk = (info >> 8) & MSK_DEV_ALL;
-               return sprintf(buf, "st->dmp_en_msk=%x\n", st->dmp_en_msk);
+               return snprintf(buf, PAGE_SIZE, "st->dmp_en_msk=%x\n",
+                               st->dmp_en_msk);
+
+       case NVI_INFO_FN_INIT:
+               if (st->hal->fn->init) {
+                       ret = st->hal->fn->init(st);
+                       return snprintf(buf, PAGE_SIZE,
+                                       "hal->fn->init() ret=%d\n", ret);
+               } else {
+                       return snprintf(buf, PAGE_SIZE,
+                                       "no hal->fn->init()\n");
+               }
 
        default:
                i = info - NVI_INFO_SNSR_SPEW;
                if (i < DEV_N)
-                       return sprintf(buf, "%s spew=%x\n",
-                                      st->snsr[i].cfg.name,
+                       return snprintf(buf, PAGE_SIZE, "%s spew=%x\n",
+                                       st->snsr[i].cfg.name,
                                       !!(st->sts & (NVI_DBG_SPEW_SNSR << i)));
                break;
        }
@@ -3891,9 +4011,10 @@ static int nvi_of_dt_pre(struct nvi_state *st, struct device_node *dn)
        }
        of_property_read_u32(dn, "bypass_timeout_ms", &st->bypass_timeout_ms);
        for (i = 0; i < DEV_N_AUX; i++) {
-               sprintf(str, "%s_push_delay_ns", st->snsr[i].cfg.name);
-               of_property_read_u32(dn, str,
-                                    (u32 *)&st->snsr[i].push_delay_ns);
+               snprintf(str, sizeof(str), "%s_push_delay_ns",
+                        st->snsr[i].cfg.name);
+               if (!of_property_read_u32(dn, str, &tmp))
+                       st->snsr[i].push_delay_ns = (s64)tmp;
        }
 
        return 0;
@@ -3918,7 +4039,8 @@ static void nvi_of_dt_post(struct nvi_state *st, struct device_node *dn)
                        tmp |= st->snsr[i].cfg.matrix[j];
                if (tmp) {
                        /* sensor has a matrix */
-                       sprintf(str, "%s_matrix_enable", st->snsr[i].cfg.name);
+                       snprintf(str, sizeof(str), "%s_matrix_enable",
+                                st->snsr[i].cfg.name);
                        if (!of_property_read_u32(dn, str, &tmp)) {
                                /* matrix override */
                                if (tmp)
@@ -3939,8 +4061,8 @@ static void nvi_of_dt_post(struct nvi_state *st, struct device_node *dn)
                st->dmp_dev_msk = st->hal->dmp->dev_msk;
                st->dmp_en_msk = st->hal->dmp->en_msk;
                for (i = 0; i < DEV_N_AUX; i++) {
-                       sprintf(str, "%s_dmp_en",
-                               st->snsr[i].cfg.name);
+                       snprintf(str, sizeof(str), "%s_dmp_en",
+                                st->snsr[i].cfg.name);
                        if (!of_property_read_u32(dn, str, &tmp)) {
                                if (tmp) {
                                        msk = 1 << i;
@@ -4047,6 +4169,8 @@ static int nvi_init(struct nvi_state *st,
        }
 
        nvi_pm(st, __func__, NVI_PM_AUTO);
+       nvi_rc_clr(st, __func__);
+       st->rc_dis = false; /* enable register cache after initialization */
        nvi_state_local = st;
        return 0;
 }
@@ -4092,6 +4216,7 @@ static int nvi_probe(struct i2c_client *client,
 
        st = &pd->st;
        i2c_set_clientdata(client, pd);
+       st->rc_dis = true; /* disable register cache during initialization */
        st->i2c = client;
        pd->i2c_dev_id = i2c_dev_id;
        /* Init fw load worker thread */
index a907f8d..4d6d6ab 100644 (file)
 #define NVI_DBG_SPEW_FIFO              (1 << (NVS_STS_EXT_N + 2))
 #define NVI_DBG_SPEW_TS                        (1 << (NVS_STS_EXT_N + 3))
 #define NVI_DBG_SPEW_SNSR              (1 << (NVS_STS_EXT_N + 4))
+
+#define NVI_RC_BANK_REG_BANK           (0x7F / 64)
+#define NVI_RC_MSK_REG_BANK            ((u64)(1ULL << (0x7F % 64)))
+
 /* register bits */
 #define BITS_SELF_TEST_EN              (0xE0)
 #define BIT_ACCEL_FCHOCIE_B            (0x08)
@@ -174,6 +178,8 @@ struct nvi_src {
        s64 ts_period;
        unsigned int period_us_src;
        unsigned int period_us_req;
+       unsigned int period_us_min;
+       unsigned int period_us_max;
        unsigned int fifo_data_n;
        u32 base_t;
 };
@@ -289,6 +295,8 @@ struct nvi_mc_icm {
        u32 data_out_ctl;
        u32 data_intr_ctl;
        u32 motion_event_ctl;
+       u32 acc_scale;
+       u32 acc_scale2;
        u32 accel_cal_rate;
        u32 ped_rate;
        u32 accel_alpha_var;
@@ -304,6 +312,7 @@ struct nvi_mc_icm {
        u32 smd_delay2_thld;
        u32 smd_timer_thld;
        u32 wom_enable;
+       u32 wtf_8a;
 };
 
 struct nvi_mc_mpu {
@@ -328,6 +337,7 @@ struct nvi_dmp {
        unsigned int fw_mem_addr;
        unsigned int fw_start;
        unsigned int dmp_reset_delay_ms;
+       int fifo_mode;
        unsigned int dev_msk;
        unsigned int en_msk;
        unsigned int dd_n;
@@ -341,7 +351,6 @@ struct nvi_dmp {
 };
 
 struct nvi_fn {
-       void (*por2rc)(struct nvi_state *st);
        int (*pm)(struct nvi_state *st, u8 pm1, u8 pm2, u8 lp);
        int (*init)(struct nvi_state *st);
        int (*st_acc)(struct nvi_state *st);
@@ -453,6 +462,7 @@ struct nvi_state {
        struct nvi_snsr snsr[DEV_N_AUX];
        struct nvi_src src[SRC_N];
        int fifo_src;
+       u64 rc_msk[8];
        bool rc_dis;
        bool mc_dis;
        bool irq_dis;
index 85da545..b7684f9 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include <linux/delay.h>
+#include <linux/kernel.h>
 #include "nvi.h"
 #include "nvi_dmp_icm.h"
 
                                         (1 << DEV_QTN) | \
                                         (1 << DEV_GMR) | \
                                         (1 << DEV_GYU))
+#define AUX_PORT_DEV_GMF               (0)
+#define MSK_AUX_PORTS_DEV_GMF          (0x3)
+#define AUX_PORT_DEV_PRS               (3)
+#define MSK_AUX_PORTS_DEV_PRS          (0x8)
+#define MSK_EN_AUX_PORTS               (((1 << (AUX_PORT_IO + DEV_N_AUX)) - \
+                                         1) & ~MSK_DEV_SNSR)
+
 #define DEFAULT_ACCEL_GAIN             (0x02000000)
 #define PED_ACCEL_GAIN                 (0x04000000)
 #define DMP_ACC_PERIOD_US_PED          (19608)
@@ -27,7 +35,6 @@
 #define DMP_HDR1_HDR2_MSK              (0x0008)
 #define DMP_HDR1_PUSH_MSK              (0xFEF0)
 #define DMP_DATA_OUT_CTL_HDR2_MSK      (0x0000FFFF)
-#define DMP_DATA_OUT_CTL_HDR2_BIT      (0x00080000)
 
 
 struct nvi_dmp_dev {
@@ -38,12 +45,14 @@ struct nvi_dmp_dev {
        unsigned int period_us_dflt;
        unsigned int buf_n;
        int buf_shft;
-       u32 out_ctl;
-       u16 int_ctl;
+       u32 int_ctl;
        u16 odr_cfg;
        u16 odr_cntr;
-       int (*fn_init)(struct nvi_state *st, unsigned int en_msk,
-                      u32 *out_ctl);
+       unsigned int odr_src;
+       int (*fn_init)(struct nvi_state *st, u32 *out_ctl,
+                      unsigned int en_msk, unsigned int irq_msk);
+       int (*fn_initd)(struct nvi_state *st, u32 *out_ctl,
+                       unsigned int en_msk, unsigned int irq_msk);
 };
 
 struct nvi_dmp_hdr {
@@ -54,6 +63,64 @@ struct nvi_dmp_hdr {
 };
 
 
+struct inv_dmp_acc_scale {
+       u32 scale;
+       u32 scale2;
+};
+
+/* input param: fsr for accel parts
+ * 1: 1g. 2: 2g. 4: 4g. 8: 8g. 16: 16g. 32: 32g.
+ * The goal is to set 1g data to 2^25, 2g data to 2^26, etc.
+ * For 2g parts, raw accel data is 1g = 2^14, 2g = 2^15.
+ * DMP takes raw accel data and shifts by 16 bits, so this scale means to shift
+ * by -5 bits.
+ * In Q-30 math, >> 5 equals multiply by 2^25 = 33554432.
+ * For 8g parts, raw accel data is 4g = 2^14, 8g = 2^15.
+ * DMP takes raw accel data and shifts by 16 bits, so this scale means to shift
+ * by -3 bits.
+ * In Q-30 math, >> 3 equals multiply by 2^27 = 134217728.
+ */
+static struct inv_dmp_acc_scale inv_dmp_acc_scales[] = {
+       {
+               .scale                  = 0x02000000,
+               .scale2                 = 0x00080000,
+       },
+       {
+               .scale                  = 0x04000000,
+               .scale2                 = 0x00040000,
+       },
+       {
+               .scale                  = 0x08000000,
+               .scale2                 = 0x00020000,
+       },
+       {
+               .scale                  = 0x10000000,
+               .scale2                 = 0x00010000,
+       },
+};
+
+static int nvi_dmp_acc_init(struct nvi_state *st, u32 *out_ctl,
+                           unsigned int en_msk, unsigned int irq_msk)
+{
+       int ret = 0;
+#if ICM_DMP_FW_VER == 2
+       unsigned int i;
+
+       i = st->snsr[DEV_ACC].usr_cfg;
+       ret |= nvi_mem_wr_be_mc(st, ACC_SCALE, 4,
+                               inv_dmp_acc_scales[i].scale,
+                               &st->mc.icm.acc_scale);
+       ret |= nvi_mem_wr_be_mc(st, ACC_SCALE2, 4,
+                               inv_dmp_acc_scales[i].scale2,
+                               &st->mc.icm.acc_scale2);
+#endif /* ICM_DMP_FW_VER */
+       ret |= st->hal->fn->en_acc(st);
+       if (irq_msk & (1 << DEV_ACC) || en_msk & ((1 << DEV_QTN) |
+                                                 (1 << DEV_GMR)))
+               *out_ctl |= ACCEL_ACCURACY_SET;
+       return ret;
+}
+
 struct inv_dmp_acc_wtf {
        unsigned int period_us;
        unsigned int rate;
@@ -100,8 +167,8 @@ static struct inv_dmp_acc_wtf inv_dmp_acc_wtfs[] = {
        },
 };
 
-static int nvi_dmp_acc_init(struct nvi_state *st, unsigned int en_msk,
-                           u32 *out_ctl)
+static int nvi_dmp_acc_initd(struct nvi_state *st, u32 *out_ctl,
+                            unsigned int en_msk, unsigned int irq_msk)
 {
        unsigned int min_diff = -1;
        unsigned int tmp;
@@ -109,7 +176,6 @@ static int nvi_dmp_acc_init(struct nvi_state *st, unsigned int en_msk,
        unsigned int j;
        int ret;
 
-       ret = st->hal->fn->en_acc(st);
        i = ARRAY_SIZE(inv_dmp_acc_wtfs) - 1;
        if (st->src[SRC_ACC].period_us_src > inv_dmp_acc_wtfs[i].period_us) {
                /* i = ARRAY_SIZE(inv_dmp_acc_wtfs) - 1 */
@@ -127,9 +193,8 @@ static int nvi_dmp_acc_init(struct nvi_state *st, unsigned int en_msk,
                }
        }
 
-       ret |= nvi_mem_wr_be_mc(st, ACCEL_CAL_RATE, 2,
-                               inv_dmp_acc_wtfs[i].rate,
-                               &st->mc.icm.accel_cal_rate);
+       ret = nvi_mem_wr_be_mc(st, ACCEL_CAL_RATE, 2, inv_dmp_acc_wtfs[i].rate,
+                              &st->mc.icm.accel_cal_rate);
        ret |= nvi_mem_wr_be_mc(st, PED_RATE, 4, inv_dmp_acc_wtfs[i].rate,
                                &st->mc.icm.ped_rate);
        ret |= nvi_mem_wr_be_mc(st, ACCEL_ALPHA_VAR, 4,
@@ -143,6 +208,27 @@ static int nvi_dmp_acc_init(struct nvi_state *st, unsigned int en_msk,
        return ret;
 }
 
+/* gmf = GeoMagnetic Field (compass) */
+static int nvi_dmp_gmf_init(struct nvi_state *st, u32 *out_ctl,
+                           unsigned int en_msk, unsigned int irq_msk)
+{
+       if (st->aux.port[AUX_PORT_DEV_GMF].nmp.type !=
+                                                 SECONDARY_SLAVE_TYPE_COMPASS)
+               /* disable without error if no compass */
+               return 1;
+
+       if (!st->aux.port[AUX_PORT_DEV_GMF].nmp.handler)
+               /* no handler */
+               return 1;
+
+       st->src[SRC_AUX].period_us_max =
+                                      st->hal->src[SRC_AUX].period_us_min * 8;
+       if (irq_msk & (1 << (AUX_PORT_DEV_GMF + DEV_N_AUX)) ||
+                                                      en_msk & (1 << DEV_GMR))
+               *out_ctl |= CPASS_ACCURACY_SET;
+       return 0;
+}
+
 struct inv_dmp_gmf_wtf {
        unsigned int period_us;
        unsigned int ct;
@@ -196,8 +282,8 @@ static struct inv_dmp_gmf_wtf inv_dmp_gmf_wtfs[] = {
 };
 
 /* gmf = GeoMagnetic Field (compass) */
-static int nvi_dmp_gmf_init(struct nvi_state *st, unsigned int en_msk,
-                           u32 *out_ctl)
+static int nvi_dmp_gmf_initd(struct nvi_state *st, u32 *out_ctl,
+                            unsigned int en_msk, unsigned int irq_msk)
 {
        unsigned int min_diff = -1;
        unsigned int tmp;
@@ -205,10 +291,6 @@ static int nvi_dmp_gmf_init(struct nvi_state *st, unsigned int en_msk,
        unsigned int j;
        int ret;
 
-       if (st->aux.port[0].nmp.type != SECONDARY_SLAVE_TYPE_COMPASS)
-               /* DMP shouldn't run if AUX device not supported */
-               return -EINVAL;
-
        i = ARRAY_SIZE(inv_dmp_gmf_wtfs) - 1;
        if (st->src[SRC_AUX].period_us_src > inv_dmp_gmf_wtfs[i].period_us) {
                /* i = ARRAY_SIZE(inv_dmp_gmf_wtfs) - 1 */
@@ -229,38 +311,48 @@ static int nvi_dmp_gmf_init(struct nvi_state *st, unsigned int en_msk,
        ret = nvi_mem_wr_be_mc(st, CPASS_TIME_BUFFER, 2,
                               inv_dmp_gmf_wtfs[i].ct,
                               &st->mc.icm.cpass_time_buffer);
+       ret |= nvi_mem_wr_be_mc(st,
+                               CPASS_RADIUS_3D_THRESH_ANOMALY, 4,
+                               inv_dmp_gmf_wtfs[i].rad_3d,
+                               &st->mc.icm.cpass_rad_3d_thr);
+#if ICM_DMP_FW_VER == 0
        ret |= nvi_mem_wr_be_mc(st, CPASS_ALPHA_VAR, 4,
                                inv_dmp_gmf_wtfs[i].alpha_c,
                                &st->mc.icm.cpass_alpha_var);
        ret |= nvi_mem_wr_be_mc(st, CPASS_A_VAR, 4,
                                inv_dmp_gmf_wtfs[i].a_c,
                                &st->mc.icm.cpass_a_var);
-       ret |= nvi_mem_wr_be_mc(st,
-                               CPASS_RADIUS_3D_THRESH_ANOMALY, 4,
-                               inv_dmp_gmf_wtfs[i].rad_3d,
-                               &st->mc.icm.cpass_rad_3d_thr);
        ret |= nvi_mem_wr_be_mc(st, CPASS_NOMOT_VAR_THRESH, 4,
                                inv_dmp_gmf_wtfs[i].nomot_var_thr,
                                &st->mc.icm.cpass_nomot_var_thr);
+#endif /* ICM_DMP_FW_VER */
        return ret;
 }
 
 /* prs = pressure */
-static int nvi_dmp_prs_init(struct nvi_state *st, unsigned int en_msk,
-                           u32 *out_ctl)
+static int nvi_dmp_prs_init(struct nvi_state *st, u32 *out_ctl,
+                           unsigned int en_msk, unsigned int irq_msk)
 {
-       return 1;
+       if (st->aux.port[AUX_PORT_DEV_PRS].nmp.type !=
+                                                SECONDARY_SLAVE_TYPE_PRESSURE)
+               /* disable without error if no pressure */
+               return 1;
+
+       return 0;
 }
 
-static int nvi_dmp_gyr_init(struct nvi_state *st, unsigned int en_msk,
-                           u32 *out_ctl)
+static int nvi_dmp_gyr_init(struct nvi_state *st, u32 *out_ctl,
+                           unsigned int en_msk, unsigned int irq_msk)
 {
+       if (irq_msk & (1 << DEV_GYR) || en_msk & ((1 << DEV_QTN) |
+                                                 (1 << DEV_GMR)))
+               *out_ctl |= GYRO_ACCURACY_SET;
        st->snsr[DEV_GYR].sts = 1;
        return st->hal->fn->en_gyr(st);
 }
 
-static int nvi_dmp_sm_init(struct nvi_state *st, unsigned int en_msk,
-                          u32 *out_ctl)
+static int nvi_dmp_sm_init(struct nvi_state *st, u32 *out_ctl,
+                          unsigned int en_msk, unsigned int irq_msk)
 {
 #if ICM_DMP_FW_VER == 0
        int ret;
@@ -275,71 +367,79 @@ static int nvi_dmp_sm_init(struct nvi_state *st, unsigned int en_msk,
                                st->snsr[DEV_SM].cfg.delay_us_max,
                                &st->mc.icm.smd_delay2_thld);
        return ret;
-#else /* ICM_DMP_FW_VER */
-       /* ICM_DMP_FW_VER == 1 */
+#elif ICM_DMP_FW_VER == 1
        return nvi_mem_wr_be_mc(st, SMD_TIMER_THLD, 4,
                                st->snsr[DEV_SM].cfg.thresh_hi,
                                &st->mc.icm.smd_timer_thld);
+#elif ICM_DMP_FW_VER == 2
+       return nvi_mem_wr_be_mc(st, SMD_CNTR_TH, 4,
+                               st->snsr[DEV_SM].cfg.thresh_hi,
+                               &st->mc.icm.smd_timer_thld);
+#else
+       return 0;
 #endif /* ICM_DMP_FW_VER */
 }
 
-static int nvi_dmp_gmr_init(struct nvi_state *st, unsigned int en_msk,
-                           u32 *out_ctl)
+static int nvi_dmp_gmr_init(struct nvi_state *st, u32 *out_ctl,
+                           unsigned int en_msk, unsigned int irq_msk)
 {
-       if (out_ctl) {
-               if (en_msk & ((1 << DEV_GYR) | (1 << DEV_GYU)))
-                       /* if gyro is enabled GMR becomes QTN 9-axis */
-                       *out_ctl |= 0x04000000;
-               else
-                       *out_ctl |= 0x04000200;
-       }
+       if (en_msk & ((1 << DEV_GYR) | (1 << DEV_GYU)))
+               /* if gyro is enabled GMR becomes QTN 9-axis */
+               st->src[SRC_AUX].period_us_min =
+                                      st->hal->src[SRC_AUX].period_us_min * 2;
+       else
+               /* gyro not enabled so GMR enabled */
+               *out_ctl |= GEOMAG_EN;
        return 0;
 }
 
 static struct nvi_dmp_dev nvi_dmp_devs[] = {
        {
                .dev                    = DEV_ACC,
+#if ICM_DMP_FW_VER == 2
+               .buf_n                  = 6,
+               .buf_shft               = 0,
+#else /* ICM_DMP_FW_VER < 2 */
                .buf_n                  = 12,
                .buf_shft               = -11,
-               .out_ctl                = 0x80004000,
+#endif /* ICM_DMP_FW_VER */
                .int_ctl                = ACCEL_SET,
                .odr_cfg                = ODR_ACCEL,
                .odr_cntr               = ODR_CNTR_ACCEL,
+               .odr_src                = SRC_ACC,
                .fn_init                = &nvi_dmp_acc_init,
+               .fn_initd               = &nvi_dmp_acc_initd,
        },
        {
                .dev                    = DEV_GYR,
-               .depend_msk             = (1 << DEV_GYU),
                .buf_n                  = 12,
-               .out_ctl                = 0x00402000,
                .int_ctl                = GYRO_CALIBR_SET,
                .odr_cfg                = ODR_GYRO_CALIBR,
                .odr_cntr               = ODR_CNTR_GYRO_CALIBR,
+               .odr_src                = SRC_GYR,
                .fn_init                = &nvi_dmp_gyr_init,
        },
        {
                .dev                    = DEV_GYU,
                .depend_msk             = (1 << DEV_GYR),
                .buf_n                  = 6,
-               .out_ctl                = 0x40000000,
                .int_ctl                = GYRO_SET,
                .odr_cfg                = ODR_GYRO,
                .odr_cntr               = ODR_CNTR_GYRO,
+               .odr_src                = SRC_GYR,
        },
        {
                .dev                    = DEV_QTN,
                .depend_msk             = (1 << DEV_ACC) |
-                                         (1 << DEV_GYR) |
-                                         (1 << DEV_GYU),
+                                         (1 << DEV_GYR),
                .src_msk                = (1 << SRC_ACC) |
-                                         (1 << SRC_GYR) |
-                                         (1 << SRC_AUX),
+                                         (1 << SRC_GYR),
                .period_us_dflt         = ICM_DMP_PERIOD_US,
                .buf_n                  = 12,
-               .out_ctl                = 0x08000000,
                .int_ctl                = QUAT6_SET,
                .odr_cfg                = ODR_QUAT6,
                .odr_cntr               = ODR_CNTR_QUAT6,
+               .odr_src                = SRC_GYR,
        },
        {
                .dev                    = DEV_GMR,
@@ -353,6 +453,7 @@ static struct nvi_dmp_dev nvi_dmp_devs[] = {
                .int_ctl                = QUAT9_SET,
                .odr_cfg                = ODR_QUAT9,
                .odr_cntr               = ODR_CNTR_QUAT9,
+               .odr_src                = SRC_ACC,
                .fn_init                = &nvi_dmp_gmr_init,
        },
        {
@@ -365,24 +466,24 @@ static struct nvi_dmp_dev nvi_dmp_devs[] = {
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = 0,
-               .depend_msk             = (0x03 << DEV_N_AUX),
+               .aux_port               = AUX_PORT_DEV_GMF,
+               .depend_msk             = (MSK_AUX_PORTS_DEV_GMF << DEV_N_AUX),
                .buf_n                  = 6,
-               .out_ctl                = 0x20001000,
                .int_ctl                = CPASS_SET,
                .odr_cfg                = ODR_CPASS,
                .odr_cntr               = ODR_CNTR_CPASS,
+               .odr_src                = SRC_AUX,
                .fn_init                = &nvi_dmp_gmf_init,
+               .fn_initd               = &nvi_dmp_gmf_initd,
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = 2,
-               .depend_msk             = (0x0C << DEV_N_AUX),
+               .aux_port               = AUX_PORT_DEV_PRS,
                .buf_n                  = 6,
-               .out_ctl                = 0x00800000,
                .int_ctl                = PRESSURE_SET,
                .odr_cfg                = ODR_PRESSURE,
                .odr_cntr               = ODR_CNTR_PRESSURE,
+               .odr_src                = SRC_AUX,
                .fn_init                = &nvi_dmp_prs_init,
        },
 };
@@ -392,23 +493,23 @@ static struct nvi_dmp_hdr nvi_dmp_hdr2s[] = {
        {
                .dev                    = DEV_ACC,
                .data_n                 = 2,
-               .hdr_msk                = 0x4000,
+               .hdr_msk                = ACCEL_ACCURACY_SET,
        },
        {
                .dev                    = DEV_GYR,
                .data_n                 = 2,
-               .hdr_msk                = 0x2000,
+               .hdr_msk                = GYRO_ACCURACY_SET,
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = 0,
+               .aux_port               = AUX_PORT_DEV_GMF,
                .data_n                 = 2,
-               .hdr_msk                = 0x1000,
+               .hdr_msk                = CPASS_ACCURACY_SET,
        },
        {
-               .dev                    = -1,
+               .dev                    = -1, /* WTF */
                .data_n                 = 6,
-               .hdr_msk                = 0x0080,
+               .hdr_msk                = ACT_RECOG_SET,
        },
 };
 
@@ -416,61 +517,65 @@ static struct nvi_dmp_hdr nvi_dmp_hdr2s[] = {
 static struct nvi_dmp_hdr nvi_dmp_hdr1s[] = {
        {
                .dev                    = DEV_ACC,
+#if ICM_DMP_FW_VER == 2
+               .data_n                 = 6,
+#else /* ICM_DMP_FW_VER < 2 */
                .data_n                 = 12,
-               .hdr_msk                = 0x8000,
+#endif /* ICM_DMP_FW_VER */
+               .hdr_msk                = ACCEL_SET,
        },
        {
                .dev                    = DEV_GYU,
                .data_n                 = 6,
-               .hdr_msk                = 0x4000,
+               .hdr_msk                = GYRO_SET,
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = 0,
+               .aux_port               = AUX_PORT_DEV_GMF,
                .data_n                 = 6,
-               .hdr_msk                = 0x2000,
+               .hdr_msk                = CPASS_SET,
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = -1,
+               .aux_port               = -1, /* ALS */
                .data_n                 = 8,
-               .hdr_msk                = 0x1000,
+               .hdr_msk                = ALS_SET,
        },
        {
                .dev                    = DEV_QTN,
                .data_n                 = 12,
-               .hdr_msk                = 0x0800,
+               .hdr_msk                = QUAT6_SET,
        },
        {
                .dev                    = DEV_GMR,
                .data_n                 = 14,
-               .hdr_msk                = 0x0400,
+               .hdr_msk                = QUAT9_SET,
        },
        {
                .dev                    = -1, /* PQUAT6 */
                .data_n                 = 6,
-               .hdr_msk                = 0x0200,
+               .hdr_msk                = PQUAT6_SET,
        },
        {
                .dev                    = DEV_AUX,
-               .aux_port               = 2,
+               .aux_port               = AUX_PORT_DEV_PRS,
                .data_n                 = 6,
-               .hdr_msk                = 0x0080,
+               .hdr_msk                = PRESSURE_SET,
        },
        {
                .dev                    = DEV_GYR,
                .data_n                 = 12,
-               .hdr_msk                = 0x0040,
+               .hdr_msk                = GYRO_CALIBR_SET,
        },
        {
                .dev                    = -1, /* CPASS_CALIBR */
                .data_n                 = 12,
-               .hdr_msk                = 0x0020,
+               .hdr_msk                = CPASS_CALIBR_SET,
        },
        {
                .dev                    = DEV_STP,
                .data_n                 = 4,
-               .hdr_msk                = 0x0010,
+               .hdr_msk                = PED_STEPDET_SET,
        },
 };
 
@@ -652,30 +757,62 @@ static int nvi_dmp_clk_n(struct nvi_state *st, u32 *clk_n)
        return nvi_mem_rd_le(st, DMPRATE_CNTR, 4, clk_n);
 }
 
-static int nvi_dmp_period(struct nvi_state *st, unsigned int en_msk)
+static unsigned int nvi_dmp_gmf_us_periods[] = {
+       200000,
+       166667,
+       142857,
+       125000,
+       111111,
+       100000,
+       90909,
+       83333,
+       76923,
+       71429,
+       66667,
+       58824,
+       55556,
+       45455,
+       40000,
+       35714,
+       31250,
+       27027,
+       22222,
+       19608,
+       13333,
+       9804,
+       4444,
+};
+
+static int nvi_dmp_period(struct nvi_state *st, u32 *out_ctl,
+                         unsigned int en_msk, unsigned int irq_msk)
 {
        struct nvi_dmp_dev *dd;
-       u16 int_ctl = 0;
+       u32 int_ctl;
        u16 odr_cfg;
        unsigned int period_us_req[SRC_N];
        unsigned int period_us;
-       unsigned int period_us_int = -1;
+       unsigned int period_us_int;
+       unsigned int dev_msk;
        unsigned int src_msk;
        unsigned int src;
        unsigned int i;
-       unsigned int j = -1;
+       unsigned int j;
        int ret;
        int ret_t = 0;
 
+       /* sensor enabled = sensor enabled by HAL (irq_msk)
+        * sensor active = sensor on as dependency to another sensor
+        */
        /* initialize source period */
        for (src = 0; src < st->hal->src_n; src++)
                period_us_req[src] = st->hal->src[src].period_us_max;
 
-       /* set source's period_us_req[] to fastest DMP device */
+       /* set source's period_us_req[] to fastest enabled sensor */
        for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++) {
                dd = &nvi_dmp_devs[i];
-               if ((!st->snsr[dd->dev].period_us) || !(en_msk &
+               if ((!st->snsr[dd->dev].period_us) || !(irq_msk &
                                                        (1 << dd->dev)))
+                       /* sensor not enabled or non-valid period */
                        continue;
 
                src_msk = dd->src_msk; /* use all of device's sources */
@@ -683,27 +820,18 @@ static int nvi_dmp_period(struct nvi_state *st, unsigned int en_msk)
                        src_msk |= (1 << st->hal->dev[dd->dev]->src);
                for (src = 0; src < st->hal->src_n; src++) {
                        if (!(src_msk & (1 << src)))
+                               /* sensor doesn't use this source */
                                continue;
 
                        if (st->snsr[dd->dev].period_us < period_us_req[src])
                                period_us_req[src] =
                                                   st->snsr[dd->dev].period_us;
-               }
-       }
-
-       /* override above fastest speeds with any faster defaults */
-       for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++) {
-               dd = &nvi_dmp_devs[i];
-               if ((!dd->period_us_dflt) || !(en_msk & (1 << dd->dev)))
-                       continue;
-
-               src_msk = dd->src_msk; /* use all of device's sources */
-               if (st->hal->dev[dd->dev]->src >= 0)
-                       src_msk |= (1 << st->hal->dev[dd->dev]->src);
-               for (src = 0; src < st->hal->src_n; src++) {
-                       if (src_msk & (1 << src) && (dd->period_us_dflt <
-                                                    period_us_req[src]))
-                               period_us_req[src] = dd->period_us_dflt;
+                       /* override above speeds with any faster defaults */
+                       if (dd->period_us_dflt) {
+                               if (dd->period_us_dflt < period_us_req[src])
+                                       period_us_req[src] =
+                                                           dd->period_us_dflt;
+                       }
                }
        }
 
@@ -711,24 +839,42 @@ static int nvi_dmp_period(struct nvi_state *st, unsigned int en_msk)
         * SRC_AUX has timestamps set to ts_now = 0 since SRC_AUX has fixed
         * rates and can't sync with the other sources.
         */
-       period_us = -1;
-       for (src = 0; src < st->hal->src_n; src++) {
-               if (period_us_req[src] < period_us)
-                       period_us = period_us_req[src];
+       period_us = min(period_us_req[SRC_GYR], period_us_req[SRC_ACC]);
+       /* The latest INV driver implements this WAR with a twist: the gmf
+        * lookup table, nvi_dmp_gmf_us_periods.
+        */
+       if (en_msk & (1 << (DEV_N_AUX + AUX_PORT_DEV_GMF))) {
+               /* compass is enabled */
+               if (period_us_req[SRC_AUX] <= period_us) {
+                       j = ARRAY_SIZE(nvi_dmp_gmf_us_periods) - 1;
+                       for (i = 0; i < j; i++) {
+                               if (period_us_req[SRC_AUX] >=
+                                                    nvi_dmp_gmf_us_periods[i])
+                                       break;
+                       }
+                       period_us = nvi_dmp_gmf_us_periods[i];
+               }
+
+               period_us_req[SRC_AUX] = period_us;
        }
-       for (src = 0; src < st->hal->src_n; src++)
-               period_us_req[src] = period_us;
+
+       period_us_req[SRC_GYR] = period_us;
+       period_us_req[SRC_ACC] = period_us;
        /* WAR: end */
 
        /* program the sources */
        for (src = 0; src < st->hal->src_n; src++) {
-               if (!(st->hal->src[src].dev_msk & en_msk))
+               dev_msk = st->hal->src[src].dev_msk;
+               if (dev_msk & (1 << DEV_AUX))
+                       dev_msk |= MSK_EN_AUX_PORTS;
+               if (!(dev_msk & en_msk))
+                       /* no active sensors use this source */
                        continue;
 
-               if (period_us_req[src] < st->hal->src[src].period_us_min)
-                       period_us_req[src] = st->hal->src[src].period_us_min;
-               if (period_us_req[src] > st->hal->src[src].period_us_max)
-                       period_us_req[src] = st->hal->src[src].period_us_max;
+               if (period_us_req[src] < st->src[src].period_us_min)
+                       period_us_req[src] = st->src[src].period_us_min;
+               if (period_us_req[src] > st->src[src].period_us_max)
+                       period_us_req[src] = st->src[src].period_us_max;
                st->src[src].period_us_req = period_us_req[src];
                switch (src) {
                case SRC_GYR:
@@ -737,6 +883,10 @@ static int nvi_dmp_period(struct nvi_state *st, unsigned int en_msk)
                                                           st->src[src].base_t;
                        if (i)
                                i--;
+/* WAR: start
+ * It appears that the latest INV ICM DMP FW runs everything off of the SRC_GYR
+ */
+#if 0 /* WAR: must program both SRC_ACC & SRC_GYR regardless if used*/
                        ret = nvi_i2c_write_rc(st, &st->hal->reg->smplrt[src],
                                               i, __func__,
                                              (u8 *)&st->rc.smplrt[src], true);
@@ -745,6 +895,26 @@ static int nvi_dmp_period(struct nvi_state *st, unsigned int en_msk)
                        else
                                st->src[src].period_us_src = ((i + 1) *
                                                   st->src[src].base_t) / 1000;
+#endif /* WAR */
+                       ret = nvi_i2c_write_rc(st,
+                                              &st->hal->reg->smplrt[SRC_GYR],
+                                              i, __func__,
+                                         (u8 *)&st->rc.smplrt[SRC_GYR], true);
+                       if (ret)
+                               ret_t |= ret;
+                       else
+                               st->src[SRC_GYR].period_us_src = ((i + 1) *
+                                              st->src[SRC_GYR].base_t) / 1000;
+                       ret = nvi_i2c_write_rc(st,
+                                              &st->hal->reg->smplrt[SRC_ACC],
+                                              i, __func__,
+                                         (u8 *)&st->rc.smplrt[SRC_ACC], true);
+                       if (ret)
+                               ret_t |= ret;
+                       else
+                               st->src[SRC_ACC].period_us_src = ((i + 1) *
+                                              st->src[SRC_ACC].base_t) / 1000;
+/* WAR: end */
                        break;
 
                case SRC_AUX:
@@ -753,43 +923,54 @@ static int nvi_dmp_period(struct nvi_state *st, unsigned int en_msk)
                }
        }
 
-       /* now set each DMP device's ODR based on their source */
+       /* now set each DMP device's ODR based on their period */
+       int_ctl = 0;
+       period_us_int = -1;
+       j = -1;
        for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++) {
                dd = &nvi_dmp_devs[i];
-               if (dd->dev >= DEV_N_AUX || !(dd->odr_cfg | dd->odr_cntr))
-                       /* dd (DMP Device) is not ODR configurable */
+               if (!(en_msk & (1 << dd->dev)))
+                       /* device disabled */
                        continue;
 
-               if (!(en_msk & (1 << dd->dev)))
+               if (dd->fn_initd)
+                       /* settings after src initialized (initd) */
+                       ret |= dd->fn_initd(st, out_ctl, en_msk, irq_msk);
+               if (dd->dev >= DEV_N_AUX || !(dd->odr_cfg | dd->odr_cntr))
+                       /* dd (DMP Device) is not ODR configurable */
                        continue;
 
                if (dd->dev == DEV_AUX) {
                        if (!(en_msk & (1 << (dd->aux_port + DEV_N_AUX))))
+                               /* AUX sensor not enabled */
                                continue;
 
                        period_us = st->aux.port[dd->aux_port].period_us;
                } else {
                        period_us = st->snsr[dd->dev].period_us;
                }
+
                if (st->bm_timeout_us) {
                        /* batch mode on */
                        int_ctl |= dd->int_ctl;
                } else {
-                       if (dd->int_ctl && period_us) {
-                               /* IRQ on fastest period */
+                       if (*out_ctl & (dd->int_ctl << 16) && period_us) {
+                               /* IRQ on fastest period with data out */
                                if (period_us < period_us_int) {
                                        period_us_int = period_us;
                                        j = i;
                                }
                        }
                }
-               src = st->hal->dev[dd->dev]->src;
-               if (src < st->hal->src_n) {
-                       odr_cfg = period_us / st->src[src].period_us_src;
+               if (irq_msk & (1 << dd->dev)) {
+                       /* ODR rate for sent sensor data */
+                       odr_cfg = period_us /
+                                           st->src[dd->odr_src].period_us_src;
                        if (odr_cfg)
                                odr_cfg--;
                } else {
-                       odr_cfg = -1;
+                       /* data is not sent so timing is synced to src */
+                       odr_cfg = 0;
                }
                if (dd->dev == DEV_AUX)
                        st->aux.port[dd->aux_port].odr = odr_cfg;
@@ -800,9 +981,9 @@ static int nvi_dmp_period(struct nvi_state *st, unsigned int en_msk)
                ret_t |= nvi_mem_wr_be(st, dd->odr_cntr, 2, 0);
        }
 
-       if (j != -1)
+       if (j < ARRAY_SIZE(nvi_dmp_devs))
                int_ctl |= nvi_dmp_devs[j].int_ctl;
-       if (en_msk & (1 << DEV_STP))
+       if (irq_msk & (1 << DEV_STP))
                int_ctl |= PED_STEPDET_SET;
        ret_t |= nvi_mem_wr_be_mc(st, DATA_INTR_CTL, 2, int_ctl,
                                  &st->mc.icm.data_intr_ctl);
@@ -848,15 +1029,19 @@ static struct nvi_dmp_dev *nvi_dd(struct nvi_state *st,
 static int nvi_dd_init(struct nvi_state *st, unsigned int dev)
 {
        struct nvi_dmp_dev *dd;
+       unsigned int en_msk;
        int ret = -EINVAL;
+       u32 out_ctl = 0;
 
        dd = nvi_dd(st, dev, -1);
        if (dd == NULL)
                return -EINVAL;
 
-       if (dd->fn_init)
-               ret = dd->fn_init(st, st->en_msk | (st->aux.dmp_en_msk <<
-                                                   DEV_N_AUX), NULL);
+       if (dd->fn_init) {
+               en_msk = st->en_msk & MSK_DEV_ALL;
+               en_msk |= (st->aux.dmp_en_msk << DEV_N_AUX);
+               ret = dd->fn_init(st, &out_ctl, en_msk, 0);
+       }
        return ret;
 }
 
@@ -893,10 +1078,11 @@ static int nvi_dmp_init_gmf(struct nvi_state *st)
        unsigned int j;
        unsigned int k;
 
-       if (st->aux.port[0].nmp.type != SECONDARY_SLAVE_TYPE_COMPASS)
+       if (st->aux.port[AUX_PORT_DEV_GMF].nmp.type !=
+                                                 SECONDARY_SLAVE_TYPE_COMPASS)
                return -EINVAL;
 
-       nmp = &st->aux.port[0].nmp;
+       nmp = &st->aux.port[AUX_PORT_DEV_GMF].nmp;
        for (i = 0; i < AXIS_N; i++) {
                for (j = 0; j < AXIS_N; j++)
                        mtrx[AXIS_N * j + i] =
@@ -970,7 +1156,10 @@ static int nvi_dmp_init(struct nvi_state *st)
 static int nvi_dd_able(struct nvi_state *st,
                       unsigned int en_msk, unsigned int irq_msk)
 {
-       u16 evnt_ctl = 0;
+#if ICM_DMP_FW_VER == 2
+       u32 wtf_8a = 0;
+#endif /* ICM_DMP_FW_VER == 2 */
+       u32 evnt_ctl = 0;
        u32 out_ctl = 0;
        struct nvi_dmp_dev *dd;
        bool en;
@@ -978,9 +1167,10 @@ static int nvi_dd_able(struct nvi_state *st,
        int ret;
 
        st->en_msk &= ~MSK_DEV_SNSR;
-       ret = nvi_dmp_period(st, en_msk);
-       if (ret)
-               return ret;
+       for (i = 0; i < st->hal->src_n; i++) {
+               st->src[i].period_us_min = st->hal->src[i].period_us_min;
+               st->src[i].period_us_max = st->hal->src[i].period_us_max;
+       }
 
        for (i = 0; i < ARRAY_SIZE(nvi_dmp_devs); i++) {
                dd = &nvi_dmp_devs[i];
@@ -997,7 +1187,8 @@ static int nvi_dd_able(struct nvi_state *st,
                }
                if (en) {
                        if (dd->fn_init) {
-                               ret = dd->fn_init(st, en_msk, &out_ctl);
+                               ret = dd->fn_init(st, &out_ctl,
+                                                 en_msk, irq_msk);
                                if (ret < 0)
                                        return ret;
 
@@ -1008,8 +1199,8 @@ static int nvi_dd_able(struct nvi_state *st,
                }
 
                if (en) {
-                       if (dd->out_ctl && (irq_msk & (1 << dd->dev)))
-                               out_ctl |= dd->out_ctl;
+                       if (dd->int_ctl && (irq_msk & (1 << dd->dev)))
+                               out_ctl |= (dd->int_ctl << 16);
                        st->snsr[dd->dev].buf_n = dd->buf_n;
                        st->snsr[dd->dev].buf_shft = dd->buf_shft;
                } else {
@@ -1021,6 +1212,12 @@ static int nvi_dd_able(struct nvi_state *st,
        }
 
        st->aux.dmp_en_msk = en_msk >> DEV_N_AUX;
+       /* WAR: run all timestamp/IRQ timing off SRC_ACC (always on) */
+       en_msk |= (1 << DEV_ACC);
+       ret = nvi_dmp_period(st, &out_ctl, en_msk, irq_msk);
+       if (ret)
+               return ret;
+
        if (st->aux.dmp_en_msk) {
                ret = nvi_aux_enable(st, __func__, true, true);
                if (ret)
@@ -1029,21 +1226,23 @@ static int nvi_dd_able(struct nvi_state *st,
 
        if (out_ctl & DMP_DATA_OUT_CTL_HDR2_MSK)
                /* header 2 needs to be enabled */
-               out_ctl |= DMP_DATA_OUT_CTL_HDR2_BIT;
+               out_ctl |= (HEADER2_SET << 16);
        ret = nvi_mem_wr_be_mc(st, DATA_OUT_CTL1, 4, out_ctl,
                               &st->mc.icm.data_out_ctl);
        if (ret)
                return ret;
 
        /* inv_enable_accel_cal_V3 */
-       /* inv_enable_gyro_cal_V3 */
        if (en_msk & (1 << DEV_ACC))
-               evnt_ctl |= (ACCEL_CAL_EN | GYRO_CAL_EN);
+               evnt_ctl |= ACCEL_CAL_EN;
+       /* inv_enable_gyro_cal_V3 */
+       if (en_msk & (1 << DEV_GYR))
+               evnt_ctl |= GYRO_CAL_EN;
        /* inv_enable_compass_cal_V3 */
-       if (en_msk & (0x03 << DEV_N_AUX))
+       if (en_msk & (1 << (DEV_N_AUX + AUX_PORT_DEV_GMF)))
                evnt_ctl |= COMPASS_CAL_EN;
        /* inv_enable_9axes_V3 */
-       if (out_ctl & CPASS_ACCURACY_MASK || en_msk & (1 << DEV_GMR))
+       if (out_ctl & CPASS_ACCURACY_SET || en_msk & (1 << DEV_GMR))
                evnt_ctl |= NINE_AXIS_EN;
        /* inv_setup_events */
        if (en_msk & (1 << DEV_STP))
@@ -1055,7 +1254,17 @@ static int nvi_dd_able(struct nvi_state *st,
        /* SMD_EN is self-clearing so we don't want it in the cache */
        st->mc.icm.motion_event_ctl &= ~SMD_EN;
        /* inv_set_wom */
-       ret |= nvi_dmp_irq(st, irq_msk & en_msk);
+       ret |= nvi_dmp_irq(st, irq_msk);
+#if ICM_DMP_FW_VER == 2
+       if (en_msk & (1 << DEV_ACC))
+               wtf_8a |= 0x02;
+       if (en_msk & (1 << DEV_GYR))
+               wtf_8a |= 0x01;
+       if (en_msk & MSK_EN_AUX_PORTS)
+               wtf_8a |= 0x08;
+       ret |= nvi_mem_wr_be_mc(st, 0x8A, 2, wtf_8a,
+                               &st->mc.icm.wtf_8a);
+#endif /* ICM_DMP_FW_VER == 2 */
        if (!ret)
                st->en_msk |= (en_msk & ((1 << DEV_N_AUX) - 1));
        return ret;
@@ -1074,6 +1283,7 @@ static int nvi_dmp_en(struct nvi_state *st)
                if (dd->dev == DEV_AUX) {
                        if (st->snsr[DEV_AUX].enable & (1 << dd->aux_port)) {
                                irq_msk |= (1 << DEV_AUX);
+                               irq_msk |= (1 << (dd->aux_port + DEV_N_AUX));
                                en_msk |= (1 << DEV_AUX);
                                en_msk |= (1 << (dd->aux_port + DEV_N_AUX));
                                en_msk |= dd->depend_msk;
@@ -1089,7 +1299,9 @@ static int nvi_dmp_en(struct nvi_state *st)
 
        if (!st->icm_dmp_war) {
                st->icm_dmp_war = true;
+               st->mc_dis = true; /* initialize cache */
                ret = nvi_dd_able(st, ICM_DMP_DEV_MSK | MSK_DEV_MPU, irq_msk);
+               st->mc_dis = false; /* enable cache */
        }
        ret |= nvi_dd_able(st, en_msk, irq_msk);
        if (!ret) {
@@ -2009,8 +2221,7 @@ static const u8 const dmp_fw_20628[] = {
        0xCA, 0xF2, 0x35, 0xF1, 0x96, 0x8F, 0xA6, 0xD9,
        0x00, 0xD8, 0xF1, 0xFF
 };
-#else /* ICM_DMP_FW_VER */
-/* ICM_DMP_FW_VER == 1 */
+#elif ICM_DMP_FW_VER == 1
 static const u8 const dmp_fw_20628[] = {
        /* bank 0: 0x0090 */
        0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -2920,6 +3131,916 @@ static const u8 const dmp_fw_20628[] = {
        0xF1, 0xCA, 0xF2, 0x35, 0xF1, 0x96, 0x8F, 0xA6,
        0xD9, 0x00, 0xD8, 0xF1, 0xFF
 };
+#else /* ICM_DMP_FW_VER == 2 */
+static const u8 const dmp_fw_20628[] = {
+       /* bank 0: 0x0090 */
+       0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00,
+       0x00, 0x05, 0x00, 0x07, 0x00, 0x05, 0x00, 0xFF,
+       0xFF, 0xF7, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
+       0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05,
+       0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40, 0x00,
+       0x20, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10, 0x00,
+       0x08, 0x00, 0x08, 0x00, 0x04, 0x00, 0x04, 0x00,
+       0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00,
+       0x00, 0x80, 0x00, 0x80, 0x00, 0x40, 0x00, 0x40,
+       0x00, 0x20, 0x00, 0x20, 0x00, 0x10, 0x00, 0x10,
+       0x00, 0x08, 0x00, 0x08, 0x00, 0x04, 0x00, 0x04,
+       0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x01,
+       /* bank 1: 0x0100 */
+       0x00, 0x00, 0x03, 0x84, 0x00, 0x00, 0x9C, 0x40,
+       0xFE, 0xF8, 0x56, 0xBE, 0x04, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x13, 0x5C, 0x28, 0xF6, 0x0C, 0xF5, 0xC2, 0x8F,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xFF, 0xF8, 0x00, 0x38,
+       0x04, 0xF6, 0xE8, 0xF4, 0x00, 0x00, 0x68, 0x00,
+       0x00, 0x01, 0xFF, 0xC7, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x47, 0xAE, 0x14,
+       0x3E, 0xB8, 0x51, 0xEC, 0x00, 0x0F, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x0C, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x2B, 0x80,
+       0x00, 0x00, 0x00, 0x52, 0x00, 0x57, 0x0A, 0x3D,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC,
+       0x00, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x50, 0x50, 0x50, 0x3F, 0xAF, 0xAF, 0xB0,
+       0x02, 0x00, 0x00, 0x00, 0x36, 0x66, 0x66, 0x66,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x2B, 0x80,
+       0x8E, 0x17, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* bank 2: 0x0200 */
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x07, 0x80,
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x3E, 0x03, 0x30, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x9C, 0x40, 0x0C, 0xCC, 0xCC, 0xCD,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x3E, 0xB8, 0x51, 0xEC, 0x01, 0x47, 0xAE, 0x14,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x33, 0x33, 0x33, 0x33, 0x0C, 0xCC, 0xCC, 0xCD,
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x4B, 0xD1,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A,
+       0x06, 0xD5, 0x8E, 0x27, 0xE1, 0x05, 0x86, 0xB2,
+       0x38, 0xB3, 0x8D, 0x1F, 0xCF, 0x87, 0xC3, 0x8F,
+       0x06, 0xD5, 0x8E, 0x27, 0x1F, 0xA1, 0xAB, 0x12,
+       0x3A, 0x50, 0xFF, 0xCB, 0x31, 0x7D, 0xD5, 0x43,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* bank 3: 0x0300 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00,
+       0x00, 0x06, 0x36, 0x38, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x8D, 0xF2,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x07, 0x00, 0x10, 0x00, 0x96, 0x00, 0x3C,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x0C, 0xC1, 0xD5, 0x21, 0xCB, 0xCF, 0x2A, 0x67,
+       0x51, 0xF6, 0x2F, 0x9C, 0xC5, 0x87, 0x95, 0xAC,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3D,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x20, 0x31, 0x88, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x0E, 0x49, 0x6E, 0x64, 0xC5, 0x92, 0x24, 0x82,
+       0x59, 0xFA, 0xEE, 0x8D, 0xC2, 0x29, 0xFE, 0xD7,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+       0x00, 0x00, 0x00, 0x14, 0x00, 0x28, 0xCC, 0xCC,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* bank 4: 0x0400 */
+       0x00, 0x00, 0x00, 0xA3, 0x00, 0x00, 0x00, 0x02,
+       0x00, 0x00, 0x00, 0x3A, 0x03, 0xE8, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x03, 0x3F, 0xC1, 0xA7, 0x68,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x80, 0x00, 0x20, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x01, 0x5E, 0x00, 0x00, 0x00, 0xFA,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x13, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, 0x05,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
+       0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x20, 0x00,
+       /* bank 5: 0x0500 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x00, 0x00,
+       0x00, 0x00, 0x61, 0xA8, 0x00, 0x00, 0x00, 0x10,
+       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+       0x00, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+       0x00, 0x40, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
+       0x00, 0x00, 0x2E, 0xE0, 0x00, 0x06, 0x40, 0x00,
+       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+       0x03, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x33, 0x33, 0x33, 0x33, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x0C, 0xCC, 0xCC, 0xCD, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x9D, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* bank 6: 0x0600 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
+       0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
+       0x00, 0x32, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x01, 0x49, 0x1B, 0x75,
+       0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x06, 0x40, 0x00, 0x00, 0x0C, 0xCD,
+       0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* bank 7: 0x0700 */
+       0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x00, 0x01,
+       0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x46,
+       0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+       0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xD4, 0xC0,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
+       0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01, 0x3C,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* bank 8: 0x0800 */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x3A, 0x98,
+       0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x01, 0x4E,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x01, 0x47, 0xAE, 0x14, 0x4E, 0x40, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x20, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x00, 0x00, 0x4E, 0x40, 0x00, 0x00,
+       0x4A, 0x40, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x06,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0xD8, 0xDC, 0xB8, 0xB0, 0xB4, 0xF3, 0xAA, 0xF8,
+       0xF9, 0xD1, 0xD9, 0x88, 0x9A, 0xF8, 0xF7, 0x3E,
+       0xD8, 0xF3, 0x8A, 0x9A, 0xA7, 0x31, 0xD1, 0xD9,
+       0xF4, 0x08, 0xF7, 0xD8, 0xF3, 0x9F, 0x31, 0xD1,
+       0xD9, 0xF4, 0x08, 0xF7, 0xDA, 0xF1, 0xFF, 0xD8,
+       0xF1, 0xA4, 0xDF, 0xA5, 0xDE, 0xF3, 0xA8, 0xDE,
+       /* bank 8: 0x0800 */
+       0xD0, 0xDF, 0xA4, 0x84, 0x9F, 0x24, 0xF2, 0xA9,
+       0xF8, 0xF9, 0xD1, 0xDA, 0xDE, 0xA8, 0xDE, 0xDF,
+       0xDF, 0xDF, 0xD8, 0xF4, 0xB1, 0x8D, 0xF3, 0xA8,
+       0xD0, 0xB0, 0xB4, 0x8F, 0xF4, 0xB9, 0xAF, 0xD0,
+       0xC7, 0xBE, 0xBE, 0xB8, 0xAE, 0xD0, 0xF3, 0x9F,
+       0x75, 0xB2, 0x86, 0xF4, 0xBE, 0xB9, 0xAF, 0xD0,
+       0xC3, 0xF1, 0xBE, 0xB8, 0xB0, 0xA3, 0xDE, 0xDF,
+       0xDF, 0xDF, 0xF2, 0xA3, 0x81, 0xC0, 0x80, 0xCD,
+       0xC7, 0xCF, 0xBC, 0xBD, 0xB4, 0xA3, 0x88, 0x93,
+       0xF1, 0x62, 0x6E, 0x76, 0x7E, 0xBE, 0xA2, 0x42,
+       0xA0, 0x4E, 0x56, 0x5E, 0xBE, 0xBE, 0xBC, 0xA3,
+       0x8B, 0x93, 0x2D, 0x55, 0x7D, 0xA2, 0x86, 0x9D,
+       0x08, 0xFD, 0x0F, 0xBC, 0xBC, 0xA3, 0x83, 0x92,
+       0x01, 0xA9, 0x9E, 0x0E, 0x16, 0x1E, 0xBE, 0xBE,
+       0x99, 0xA5, 0x2C, 0x54, 0x7C, 0xBA, 0xA5, 0x2C,
+       0x54, 0x7C, 0xBD, 0xBD, 0xBC, 0xBC, 0xB1, 0xB6,
+       0x83, 0x95, 0xA5, 0xF1, 0x0E, 0x16, 0x1E, 0xB2,
+       0xA7, 0x85, 0x95, 0x2A, 0xF0, 0x50, 0x78, 0x87,
+       0x93, 0xF1, 0x01, 0xDA, 0xA5, 0xDF, 0xDF, 0xDF,
+       0xD8, 0xA4, 0xDF, 0xDF, 0xDF, 0xB0, 0x80, 0xF2,
+       0xA4, 0xC3, 0xCB, 0xC5, 0xF1, 0xB1, 0x8E, 0x94,
+       0xA4, 0x0E, 0x16, 0x1E, 0xB2, 0x86, 0xBE, 0xA0,
+       0x2C, 0x34, 0x3C, 0xBD, 0xBD, 0xB4, 0x96, 0xB8,
+       0xA1, 0x2C, 0x34, 0x3C, 0xBD, 0xB6, 0x94, 0xBE,
+       0xA6, 0x2C, 0xFD, 0x35, 0x34, 0xFD, 0x35, 0x3C,
+       0xFD, 0x35, 0xBE, 0xBC, 0xB2, 0x8E, 0x94, 0xA6,
+       0x2D, 0x55, 0x7D, 0xBA, 0xA4, 0x2D, 0x55, 0x7D,
+       0xB8, 0xB0, 0xB4, 0xA6, 0x8F, 0x96, 0x2E, 0x36,
+       0x3E, 0xBC, 0xBC, 0xBD, 0xA6, 0x86, 0x9F, 0xF5,
+       0x34, 0x54, 0x74, 0xBC, 0xBE, 0xF1, 0x90, 0xFC,
+       0xC3, 0x00, 0xD9, 0xF4, 0x0A, 0x5A, 0xD8, 0xF3,
+       0xA0, 0xDF, 0xF1, 0xBC, 0x86, 0x91, 0xA9, 0x2D,
+       /* bank 9: 0x0900 */
+       0x55, 0x7D, 0xBC, 0xBC, 0xA9, 0x80, 0x90, 0xFC,
+       0x51, 0x00, 0x10, 0xFC, 0x51, 0x00, 0x10, 0xFC,
+       0x51, 0x00, 0x10, 0xFC, 0xC1, 0x04, 0xD9, 0xF2,
+       0xA0, 0xDF, 0xF4, 0x0A, 0x5A, 0xD8, 0xF6, 0xA0,
+       0xFA, 0x80, 0x90, 0x38, 0xF3, 0xDE, 0xDA, 0xF8,
+       0xF4, 0x0A, 0x5A, 0xD8, 0xF1, 0xBD, 0x95, 0xFC,
+       0xC1, 0x04, 0xD9, 0xBD, 0xBD, 0xF4, 0x0A, 0x5A,
+       0xDA, 0xBD, 0xBD, 0xD8, 0xF6, 0xBC, 0xBC, 0xBD,
+       0xBD, 0xBE, 0xBE, 0xB5, 0xA7, 0x84, 0x92, 0x1A,
+       0xF8, 0xF9, 0xD1, 0xDB, 0x84, 0x93, 0xF7, 0x6A,
+       0xB6, 0x87, 0x96, 0xF3, 0x09, 0xFF, 0xDA, 0xBC,
+       0xBD, 0xBE, 0xD8, 0xF3, 0xBC, 0xBC, 0xBD, 0xBD,
+       0xBE, 0xBE, 0xB9, 0xB2, 0xA9, 0x80, 0xCD, 0xF2,
+       0xC4, 0xC5, 0xBA, 0xF3, 0xA0, 0xD0, 0xDE, 0xB1,
+       0xB4, 0xF7, 0xA7, 0x89, 0x91, 0x72, 0x89, 0x91,
+       0x47, 0xB6, 0x97, 0x4A, 0xB9, 0xF2, 0xA9, 0xD0,
+       0xFA, 0xF9, 0xD1, 0xD9, 0xF4, 0x0A, 0x8E, 0xD8,
+       0xF3, 0xBA, 0xA7, 0xF9, 0xDB, 0xFB, 0xD9, 0xF1,
+       0xB9, 0xB0, 0x81, 0xA9, 0xC3, 0xF2, 0xC5, 0xF3,
+       0xBA, 0xA0, 0xD0, 0xF8, 0xD8, 0xF1, 0xB1, 0x89,
+       0xA7, 0xDF, 0xDF, 0xDF, 0xF2, 0xA7, 0xC3, 0xCB,
+       0xC5, 0xF1, 0xB2, 0xB5, 0xB9, 0x87, 0x97, 0xA5,
+       0x22, 0xF0, 0x48, 0x70, 0x3C, 0x98, 0x40, 0x68,
+       0x34, 0x58, 0x99, 0x60, 0xF1, 0xBC, 0xB3, 0x8E,
+       0x95, 0xAA, 0x25, 0x4D, 0x75, 0xBC, 0xBC, 0xB8,
+       0xB0, 0xB4, 0xA7, 0x88, 0x9F, 0xF7, 0x5A, 0xF9,
+       0xD9, 0xF1, 0xBA, 0xA5, 0xDF, 0xDF, 0xDF, 0xB8,
+       0xDA, 0xF3, 0xA8, 0xF8, 0x88, 0x9D, 0xD0, 0x7C,
+       0xD8, 0xF7, 0xA7, 0x88, 0x9F, 0x52, 0xF9, 0xD9,
+       0xF1, 0xBA, 0xA4, 0xDF, 0xDF, 0xDF, 0xB8, 0xDA,
+       0xF3, 0xA8, 0x88, 0x9C, 0xD0, 0xDF, 0x68, 0x70,
+       0x9D, 0x60, 0x70, 0x78, 0xD8, 0xF7, 0xA7, 0x88,
+       /* bank 10: 0x0A00 */
+       0x9F, 0x42, 0xF9, 0xBA, 0xA0, 0xD0, 0xF3, 0xD9,
+       0xDE, 0xD8, 0xF8, 0xF9, 0xD1, 0xB8, 0xDA, 0xA8,
+       0x88, 0x9E, 0xD0, 0x64, 0x68, 0xD8, 0xA8, 0x84,
+       0x98, 0xD0, 0xF7, 0x7E, 0xF0, 0xB2, 0xB6, 0xBA,
+       0x85, 0x91, 0xA7, 0x24, 0x70, 0x59, 0x44, 0x69,
+       0x38, 0x64, 0x48, 0x31, 0x2D, 0x51, 0x79, 0x87,
+       0xF1, 0xA1, 0x00, 0x2C, 0x54, 0x7C, 0xF0, 0x81,
+       0xA7, 0x04, 0x28, 0x50, 0x78, 0xFD, 0x7F, 0xF1,
+       0xA7, 0x87, 0x96, 0x59, 0x91, 0xA1, 0x02, 0x0E,
+       0x16, 0x1E, 0xF0, 0x84, 0x91, 0xA7, 0x24, 0x70,
+       0x59, 0x44, 0x69, 0x38, 0x64, 0x48, 0x31, 0x2D,
+       0x51, 0x79, 0xA2, 0x87, 0x0D, 0x20, 0x59, 0x70,
+       0x15, 0x38, 0x40, 0x69, 0xA4, 0xF1, 0x62, 0xF0,
+       0x19, 0x31, 0x48, 0xB8, 0xB1, 0xB4, 0xF1, 0xA6,
+       0x80, 0xC6, 0xF4, 0xB0, 0x81, 0xF3, 0xA7, 0xC6,
+       0xB1, 0x8F, 0x97, 0xF7, 0x02, 0xF9, 0xDA, 0xF4,
+       0x0B, 0xBD, 0xD8, 0xB0, 0xF7, 0xA7, 0x88, 0x9F,
+       0x52, 0xF9, 0xD9, 0xF4, 0x0B, 0xB6, 0xD8, 0xF1,
+       0xB2, 0xB6, 0xA6, 0x82, 0x92, 0x2A, 0xF0, 0x50,
+       0xFD, 0x08, 0xF1, 0xA7, 0x84, 0x94, 0x02, 0xFD,
+       0x08, 0xB0, 0xB4, 0x86, 0x97, 0x00, 0xB1, 0xBA,
+       0xA7, 0x81, 0x61, 0xD9, 0xF4, 0x0B, 0xF3, 0xD8,
+       0xF1, 0x41, 0xDA, 0xF4, 0x0B, 0xF3, 0xD8, 0xF1,
+       0xB8, 0xB2, 0xA6, 0x82, 0xC0, 0xD8, 0xF1, 0xB0,
+       0xB6, 0x86, 0x92, 0xA7, 0x16, 0xFD, 0x04, 0x0F,
+       0xFD, 0x04, 0xF0, 0xBA, 0x87, 0x91, 0xA7, 0x24,
+       0x58, 0x3D, 0x40, 0x34, 0x49, 0x2D, 0x51, 0xB2,
+       0x87, 0xF1, 0xA1, 0x00, 0x2C, 0x54, 0x7C, 0xF0,
+       0x81, 0xA7, 0x04, 0x28, 0x50, 0x78, 0xFD, 0x7F,
+       0xF1, 0xA7, 0x87, 0x96, 0x59, 0x91, 0xA1, 0x02,
+       0x0E, 0x16, 0x1E, 0xD8, 0xF7, 0xB0, 0xB4, 0xBA,
+       0x88, 0x9E, 0xA7, 0x6A, 0xF9, 0xD9, 0xF4, 0x0D,
+       /* bank 11: 0x0B00 */
+       0x0B, 0xD8, 0xF0, 0xB1, 0xB5, 0x8A, 0x9A, 0xA3,
+       0x2C, 0x50, 0x78, 0xF2, 0xA5, 0xDE, 0xF8, 0xF8,
+       0xF1, 0xB5, 0xB2, 0xA7, 0x83, 0x90, 0x21, 0xDB,
+       0xB6, 0xB1, 0x80, 0x93, 0x29, 0xD9, 0xF2, 0xA5,
+       0xF8, 0xD8, 0xF1, 0xB2, 0xB6, 0xA7, 0x83, 0x93,
+       0x31, 0xF3, 0xA5, 0xDE, 0xD9, 0xF8, 0xF8, 0xD8,
+       0xF1, 0xA9, 0x89, 0x99, 0xF0, 0x34, 0x83, 0x38,
+       0xF1, 0xA7, 0x29, 0xF5, 0x87, 0x90, 0x18, 0xD9,
+       0xF3, 0xA5, 0xF8, 0xD8, 0xA8, 0x80, 0x91, 0xF0,
+       0x0C, 0x31, 0x14, 0x28, 0x1C, 0x20, 0x04, 0x39,
+       0xA7, 0x88, 0x98, 0x04, 0x28, 0x51, 0x79, 0x1D,
+       0x30, 0x14, 0x38, 0xB1, 0xB8, 0x8A, 0xA7, 0xD0,
+       0x97, 0x2C, 0x50, 0x50, 0x78, 0x78, 0xBC, 0xBA,
+       0xB0, 0xA7, 0x85, 0x98, 0x04, 0x28, 0x50, 0x78,
+       0xF1, 0x84, 0x97, 0x29, 0xD9, 0xBE, 0xB8, 0xA5,
+       0x8D, 0x98, 0x20, 0x2C, 0x34, 0x3C, 0xBE, 0xBE,
+       0xBA, 0xAA, 0xDE, 0xDF, 0xF8, 0xF4, 0x0C, 0x95,
+       0xD8, 0xF1, 0xBA, 0xAA, 0xF8, 0xA7, 0x84, 0x9A,
+       0x01, 0xD9, 0xAA, 0xDF, 0xF8, 0xD8, 0xF1, 0xBC,
+       0xBC, 0x9A, 0xFC, 0xC1, 0x04, 0xD9, 0xAA, 0xFB,
+       0xA6, 0xB2, 0x89, 0x96, 0x42, 0xB4, 0x97, 0xF0,
+       0x78, 0xA7, 0x86, 0xF1, 0x38, 0xFD, 0x01, 0xB6,
+       0x97, 0x01, 0xA6, 0xD0, 0xB6, 0x9A, 0x52, 0x87,
+       0xF0, 0x18, 0xD8, 0xBD, 0xB0, 0xB4, 0xBA, 0x87,
+       0x96, 0xA7, 0xF5, 0x78, 0xBD, 0xBD, 0xF3, 0xD9,
+       0xA5, 0xF8, 0xD8, 0xB2, 0xB6, 0xF1, 0xA9, 0x89,
+       0x93, 0x1A, 0xB0, 0x87, 0x99, 0x60, 0xB8, 0xA7,
+       0xD0, 0xB2, 0x89, 0xC1, 0xB0, 0xBA, 0xF3, 0xA5,
+       0xF9, 0xF9, 0xB8, 0xF1, 0xDA, 0xA7, 0xD0, 0xDF,
+       0xD8, 0xA7, 0xD0, 0xFA, 0xF9, 0xD1, 0xBA, 0xDA,
+       0xA7, 0x87, 0x90, 0x6A, 0x66, 0xB2, 0xA0, 0x87,
+       0x01, 0x2C, 0xF0, 0xA7, 0x80, 0x90, 0x04, 0x28,
+       /* bank 12: 0x0C00 */
+       0xFD, 0x7F, 0xF1, 0xA7, 0x87, 0x96, 0x59, 0x90,
+       0xA0, 0x02, 0x0E, 0xD8, 0xF0, 0xBA, 0xB2, 0xB6,
+       0xA8, 0x80, 0x91, 0x0C, 0x31, 0x14, 0x28, 0x1C,
+       0x20, 0x04, 0x39, 0xD8, 0xF7, 0xB8, 0xB4, 0xB0,
+       0xA7, 0x9D, 0x88, 0x72, 0xF9, 0xBC, 0xBD, 0xBE,
+       0xD9, 0xF4, 0x0E, 0x72, 0xD8, 0xF2, 0xB8, 0xAD,
+       0xF8, 0xF9, 0xD1, 0xDA, 0xDE, 0xBA, 0xA1, 0xDE,
+       0xAE, 0xDE, 0xF8, 0xD8, 0xF2, 0xB1, 0xB5, 0xB9,
+       0xAE, 0xF9, 0xDA, 0xF4, 0x0E, 0x59, 0xD8, 0xF2,
+       0x8E, 0xC2, 0xF1, 0xB2, 0x80, 0x9A, 0xF5, 0xAF,
+       0x24, 0xD9, 0xF4, 0x0E, 0x59, 0xD8, 0xF5, 0x44,
+       0xD9, 0xF4, 0x0E, 0x59, 0xD8, 0xF5, 0x64, 0xD9,
+       0xF4, 0x0E, 0x59, 0xD8, 0xF1, 0xB1, 0xB6, 0x8B,
+       0x90, 0xAF, 0x2D, 0x55, 0x7D, 0xB5, 0x8C, 0x9F,
+       0xAD, 0x0E, 0x16, 0x1E, 0x8B, 0x9D, 0xAB, 0x2C,
+       0x54, 0x7C, 0x8D, 0x9F, 0xAA, 0x2E, 0x56, 0x7E,
+       0x8A, 0x9C, 0xAA, 0x2C, 0x54, 0x7C, 0x9B, 0xAC,
+       0x26, 0x46, 0x66, 0xAF, 0x8D, 0x9D, 0x00, 0x9C,
+       0x0D, 0xDB, 0x11, 0x8F, 0x19, 0xF4, 0x0D, 0x9B,
+       0xD8, 0x0E, 0x59, 0xD8, 0xF1, 0xB2, 0x81, 0xB6,
+       0x90, 0xAF, 0x2D, 0x55, 0x7D, 0xB1, 0x8F, 0xB5,
+       0x9F, 0xAF, 0xF5, 0x2C, 0x54, 0x7C, 0xF1, 0xB2,
+       0x8C, 0x9F, 0xAD, 0x6D, 0xDB, 0x71, 0x79, 0xF4,
+       0x0D, 0xC9, 0xD8, 0xF3, 0xBA, 0xA1, 0xDE, 0xF8,
+       0xF1, 0x80, 0xA1, 0xC3, 0xC5, 0xC7, 0xF4, 0x0D,
+       0xD8, 0xD8, 0xF3, 0xB6, 0xBA, 0x91, 0xFC, 0xC0,
+       0x28, 0xDA, 0xA1, 0xF8, 0xD9, 0xF4, 0x0E, 0x59,
+       0xD8, 0xF3, 0xB9, 0xAE, 0xF8, 0xF9, 0xD1, 0xD9,
+       0xF8, 0xF4, 0x0E, 0x59, 0xD8, 0xF1, 0xBA, 0xB1,
+       0xB5, 0xA0, 0x8B, 0x93, 0x3E, 0x5E, 0x7E, 0xAB,
+       0x83, 0xC0, 0xC5, 0xB2, 0xB6, 0xA3, 0x87, 0xC0,
+       0xC3, 0xC5, 0xC7, 0xA2, 0x88, 0xC0, 0xC3, 0xC5,
+       /* bank 13: 0x0D00 */
+       0xC7, 0xA4, 0x86, 0xC0, 0xC3, 0xC5, 0xC7, 0xA5,
+       0x85, 0xC4, 0xC7, 0xAC, 0x8D, 0xC0, 0xF3, 0xAE,
+       0xDE, 0xF8, 0xF4, 0x11, 0x36, 0xD8, 0xF1, 0xA7,
+       0x83, 0xC0, 0xC3, 0xC5, 0xC7, 0xA8, 0x82, 0xC0,
+       0xC3, 0xC5, 0xC7, 0xA6, 0x84, 0xC0, 0xC3, 0xC5,
+       0xC7, 0xA5, 0x85, 0xD0, 0xC0, 0xC3, 0x8D, 0x9D,
+       0xAF, 0x39, 0xD9, 0xF4, 0x0E, 0x59, 0xD8, 0xF1,
+       0x83, 0xB5, 0x9E, 0xAE, 0x34, 0xFD, 0x0A, 0x54,
+       0xFD, 0x0A, 0x74, 0xFD, 0x0A, 0xF2, 0xAF, 0xDE,
+       0xF8, 0xF8, 0xF8, 0xB6, 0x81, 0x9F, 0x05, 0xF8,
+       0xF9, 0xD1, 0xDA, 0x8F, 0xA1, 0xC0, 0xF4, 0x0E,
+       0x60, 0xD8, 0xF2, 0xBA, 0xAE, 0xF8, 0xF9, 0xD1,
+       0xDA, 0xF3, 0xBE, 0xBE, 0xBC, 0xBC, 0xBD, 0xBD,
+       0xB8, 0xB0, 0xB4, 0xA5, 0x85, 0x9C, 0x08, 0xBE,
+       0xBC, 0xBD, 0xD8, 0xF7, 0xBC, 0xBC, 0xBD, 0xBD,
+       0xBB, 0xB4, 0xB0, 0xAF, 0x9E, 0x88, 0x62, 0xF9,
+       0xBC, 0xBD, 0xD9, 0xF4, 0x10, 0xB4, 0xD8, 0xF1,
+       0xBC, 0xBC, 0xB1, 0x85, 0xBA, 0xB5, 0xA0, 0x98,
+       0x06, 0x26, 0x46, 0xBC, 0xB9, 0xB3, 0xB6, 0xF1,
+       0xAF, 0x81, 0x90, 0x2D, 0x55, 0x7D, 0xB1, 0xB5,
+       0xAF, 0x8F, 0x9F, 0xF5, 0x2C, 0x54, 0x7C, 0xF1,
+       0xBB, 0xAF, 0x86, 0x9F, 0x69, 0xDB, 0x71, 0x79,
+       0xDA, 0xF3, 0xA0, 0xDF, 0xF8, 0xF1, 0xA1, 0xDE,
+       0xF2, 0xF8, 0xD8, 0xB3, 0xB7, 0xF1, 0x8C, 0x9B,
+       0xAF, 0x19, 0xD9, 0xAC, 0xDE, 0xF3, 0xA0, 0xDF,
+       0xF8, 0xD8, 0xAF, 0x80, 0x90, 0x69, 0xD9, 0xA0,
+       0xFA, 0xF1, 0xB2, 0x80, 0xA1, 0xC3, 0xC5, 0xC7,
+       0xF2, 0xA0, 0xD0, 0xDF, 0xF8, 0xF4, 0x10, 0x9E,
+       0xD8, 0xF2, 0xA0, 0xD0, 0xDF, 0xF1, 0xBC, 0xBC,
+       0xB1, 0xAD, 0x8A, 0x9E, 0x26, 0x46, 0x66, 0xBC,
+       0xB3, 0xB3, 0xF3, 0xA2, 0xDE, 0xF8, 0xF4, 0x10,
+       0xBF, 0xD8, 0xF1, 0xAA, 0x8D, 0xC1, 0xF2, 0xA1,
+       /* bank 14: 0x0E00 */
+       0xF8, 0xF9, 0xD1, 0xDA, 0xF4, 0x0F, 0x2A, 0xD8,
+       0xF1, 0xAF, 0x8A, 0x9A, 0x21, 0x8F, 0x90, 0xF5,
+       0x10, 0xDA, 0xF4, 0x0F, 0x2A, 0xD8, 0xF1, 0x91,
+       0xFC, 0xC0, 0x04, 0xD9, 0xF4, 0x0F, 0x71, 0xD8,
+       0xF3, 0xA1, 0xDE, 0xF8, 0xA0, 0xDF, 0xF8, 0xF4,
+       0x10, 0x9E, 0xF3, 0x91, 0xFC, 0xC0, 0x07, 0xD9,
+       0xF4, 0x0F, 0x71, 0xD8, 0xF1, 0xAF, 0xB1, 0x84,
+       0x9C, 0x01, 0xB3, 0xB5, 0x80, 0x97, 0xDB, 0xF3,
+       0x21, 0xB9, 0xA7, 0xD9, 0xF8, 0xF4, 0x0F, 0x71,
+       0xD8, 0xF3, 0xB9, 0xA7, 0xDE, 0xF8, 0xBB, 0xF1,
+       0xA3, 0x87, 0xC0, 0xC3, 0xC5, 0xC7, 0xA4, 0x88,
+       0xC0, 0xC3, 0xC5, 0xC7, 0xA5, 0x89, 0xC0, 0xC3,
+       0xC5, 0xC7, 0xA6, 0x86, 0xC4, 0xC7, 0xA1, 0x82,
+       0xC3, 0xC5, 0xC7, 0xF3, 0xA1, 0xDE, 0xF4, 0x10,
+       0xB4, 0xD8, 0xF1, 0xBB, 0xB3, 0xB7, 0xA1, 0xF8,
+       0xF9, 0xD1, 0xDA, 0xF2, 0xA0, 0xD0, 0xDF, 0xF8,
+       0xD8, 0xF1, 0xB9, 0xB1, 0xB6, 0xA8, 0x87, 0x90,
+       0x2D, 0x55, 0x7D, 0xF5, 0xB5, 0xA8, 0x88, 0x98,
+       0x2C, 0x54, 0x7C, 0xF1, 0xAF, 0x86, 0x98, 0x29,
+       0xDB, 0x31, 0x39, 0xF4, 0x10, 0xB4, 0xD8, 0xF1,
+       0xB3, 0xB6, 0xA7, 0x8A, 0x90, 0x4C, 0x54, 0x5C,
+       0xBA, 0xA0, 0x81, 0x90, 0x2D, 0x55, 0x7D, 0xBB,
+       0xF2, 0xA2, 0xF8, 0xF9, 0xD1, 0xDA, 0xDE, 0xF4,
+       0x10, 0xB4, 0xD8, 0xF1, 0xBA, 0xB0, 0xAB, 0x8F,
+       0xC0, 0xC7, 0xB3, 0xA3, 0x83, 0xC0, 0xC3, 0xC5,
+       0xC7, 0xA2, 0x84, 0xC0, 0xC3, 0xC5, 0xC7, 0xA4,
+       0x85, 0xC0, 0xC3, 0xC5, 0xC7, 0xA5, 0x86, 0xC0,
+       0xC3, 0xAC, 0x8C, 0xC2, 0xF3, 0xAE, 0xDE, 0xF8,
+       0xF8, 0xF4, 0x11, 0x36, 0xD8, 0xF1, 0xB2, 0xBB,
+       0xA3, 0x83, 0xC0, 0xC3, 0xC5, 0xC7, 0xA4, 0x82,
+       0xC0, 0xC3, 0xC5, 0xC7, 0xA5, 0x84, 0xC0, 0xC3,
+       0xC5, 0xC7, 0xA6, 0x85, 0xC0, 0xC3, 0xAC, 0x8C,
+       /* bank 15: 0x0F00 */
+       0xC4, 0xB3, 0xB7, 0xAF, 0x85, 0x95, 0x56, 0xFD,
+       0x0F, 0x86, 0x96, 0x06, 0xFD, 0x0F, 0xF0, 0x84,
+       0x9F, 0xAF, 0x4C, 0x70, 0xFD, 0x0F, 0xF1, 0x86,
+       0x96, 0x2E, 0xFD, 0x0F, 0x84, 0x9F, 0x72, 0xFD,
+       0x0F, 0xDF, 0xAF, 0x2C, 0x54, 0x7C, 0xAF, 0x8C,
+       0x69, 0xDB, 0x71, 0x79, 0x8B, 0x9C, 0x61, 0xF4,
+       0x10, 0x35, 0xDA, 0x10, 0xB4, 0xD8, 0xF1, 0xAB,
+       0x83, 0x91, 0x28, 0xFD, 0x05, 0x54, 0xFD, 0x05,
+       0x7C, 0xFD, 0x05, 0xB8, 0xBD, 0xBD, 0xB5, 0xA3,
+       0x8B, 0x95, 0x05, 0x2D, 0x55, 0xBD, 0xB4, 0xBB,
+       0xAD, 0x8E, 0x93, 0x0E, 0x16, 0x1E, 0xB7, 0xF3,
+       0xA2, 0xDE, 0xF8, 0xF8, 0xF4, 0x10, 0xBF, 0xD8,
+       0xF2, 0xA1, 0xF8, 0xF9, 0xD1, 0xD9, 0xF1, 0xAF,
+       0x8D, 0x9A, 0x01, 0xF5, 0x8F, 0x90, 0xDB, 0x00,
+       0xF4, 0x10, 0xB4, 0xDA, 0xF1, 0xAA, 0x8D, 0xC0,
+       0xAE, 0x8B, 0xC1, 0xC3, 0xC5, 0xA1, 0xDE, 0xA7,
+       0x83, 0xC0, 0xC3, 0xC5, 0xC7, 0xA8, 0x84, 0xC0,
+       0xC3, 0xC5, 0xC7, 0xA9, 0x85, 0xC0, 0xC3, 0xC5,
+       0xC7, 0xA6, 0x86, 0xD0, 0xC0, 0xC3, 0xA2, 0x81,
+       0xC3, 0xC5, 0xC7, 0xF4, 0x10, 0xB4, 0xF1, 0xBB,
+       0xB3, 0xA3, 0xDE, 0xDF, 0xDF, 0xDF, 0xA4, 0x8C,
+       0xC4, 0xC5, 0xC5, 0xC5, 0xA5, 0xDE, 0xDF, 0xDF,
+       0xDF, 0xA6, 0xDE, 0xDF, 0xD8, 0xF3, 0xB9, 0xAE,
+       0xDF, 0xBA, 0xAE, 0xDE, 0xBB, 0xA2, 0xDE, 0xD8,
+       0xF3, 0xA2, 0xF8, 0xF9, 0xD1, 0xD9, 0xF4, 0x11,
+       0x34, 0xD8, 0xF5, 0xAD, 0x8D, 0x9D, 0x2C, 0x54,
+       0x7C, 0xF1, 0xAF, 0x49, 0xDA, 0xC3, 0xC5, 0xD9,
+       0xC5, 0xC3, 0xD8, 0xAF, 0x9F, 0x69, 0xD0, 0xDA,
+       0xC7, 0xD9, 0x8F, 0xC3, 0x8D, 0xAF, 0xC7, 0xD8,
+       0xB9, 0xA9, 0x8F, 0x9F, 0xF0, 0x54, 0x78, 0xF1,
+       0xFD, 0x0F, 0xA6, 0xB1, 0x89, 0xC2, 0xB3, 0xAF,
+       0x8F, 0x9F, 0x2E, 0xFD, 0x11, 0xB1, 0xB5, 0xA9,
+       /* bank 16: 0x1000 */
+       0x89, 0x9F, 0x2C, 0xF3, 0xAE, 0xDF, 0xF8, 0xF8,
+       0xF4, 0x12, 0xEB, 0xD8, 0xF1, 0xAD, 0x86, 0x99,
+       0x06, 0xFD, 0x10, 0xDF, 0xF8, 0xFD, 0x0F, 0xAD,
+       0x8D, 0x9D, 0x4C, 0xBB, 0xB3, 0xAD, 0x8F, 0x9D,
+       0x2A, 0xFD, 0x0F, 0xB7, 0x92, 0xFC, 0xC0, 0x04,
+       0xD9, 0xF4, 0x0E, 0xF9, 0xD8, 0xFC, 0xC0, 0x08,
+       0xD9, 0xF4, 0x10, 0x5F, 0xD8, 0xF1, 0xD8, 0xF3,
+       0xBA, 0xB2, 0xB6, 0xAE, 0xF8, 0xF9, 0xD1, 0xD9,
+       0xF4, 0x12, 0xE9, 0xD8, 0xF1, 0xAF, 0xDE, 0xF9,
+       0xFD, 0x0F, 0x80, 0x90, 0x2C, 0x54, 0x7C, 0xA0,
+       0x2A, 0xF0, 0x50, 0x78, 0xFD, 0x0F, 0xF1, 0xA2,
+       0x82, 0x9C, 0x00, 0x24, 0x44, 0x64, 0xA9, 0x8F,
+       0x94, 0xF0, 0x04, 0xFD, 0x0F, 0x0C, 0x30, 0xFD,
+       0x0F, 0x1C, 0x95, 0x20, 0x48, 0xFD, 0x0F, 0xF1,
+       0x99, 0xC1, 0x2C, 0x54, 0x7C, 0xAA, 0x82, 0x99,
+       0x02, 0xFD, 0x0F, 0x2E, 0xFD, 0x0F, 0x56, 0xFD,
+       0x0F, 0x7E, 0xFD, 0x0F, 0xAC, 0x83, 0x9F, 0xF0,
+       0x04, 0x28, 0x50, 0x78, 0xFD, 0x0F, 0x8C, 0x90,
+       0xF1, 0x21, 0xF5, 0x8C, 0x9C, 0x2C, 0xF1, 0xAF,
+       0xDE, 0xF1, 0x89, 0xAF, 0x9F, 0xFC, 0xC0, 0x00,
+       0xD9, 0xC1, 0x8A, 0xC1, 0x82, 0xC1, 0xD8, 0xFC,
+       0xC0, 0x04, 0xD9, 0xC3, 0x8A, 0xC3, 0x82, 0xC3,
+       0xD8, 0xFC, 0xC0, 0x08, 0xD9, 0xC5, 0x8A, 0xC5,
+       0x82, 0xC5, 0xD8, 0xFC, 0xC0, 0x0C, 0xD9, 0xC7,
+       0x8A, 0xC7, 0x82, 0xC7, 0xD8, 0xFC, 0xC0, 0x10,
+       0xD9, 0xF4, 0x12, 0xA3, 0xD8, 0xF1, 0x8B, 0xAB,
+       0xD0, 0xC0, 0x9F, 0x2E, 0xFD, 0x0F, 0xA0, 0xDE,
+       0xAB, 0xD0, 0x90, 0x65, 0xA0, 0x8F, 0x9F, 0x4A,
+       0xFD, 0x0F, 0xAB, 0x8B, 0x90, 0x00, 0xB9, 0xA9,
+       0xC1, 0xF3, 0xAE, 0xDF, 0xF8, 0xF4, 0x12, 0xEB,
+       0xD8, 0xF1, 0xBA, 0xB1, 0xB6, 0x89, 0xAB, 0xC1,
+       0xB2, 0xAF, 0xD0, 0x8B, 0x9F, 0x3E, 0xFD, 0x0F,
+       /* bank 17: 0x1100 */
+       0x5A, 0xFD, 0x0F, 0x9F, 0xFC, 0xC0, 0x00, 0xD9,
+       0xF1, 0x8F, 0xA2, 0xC6, 0xD8, 0xFC, 0xC0, 0x04,
+       0xD9, 0x8F, 0xA2, 0xC7, 0x84, 0xAB, 0xD0, 0xC0,
+       0xAF, 0x8A, 0x9B, 0x1E, 0xFD, 0x0F, 0x36, 0xFD,
+       0x0F, 0xA4, 0x8F, 0x30, 0xAA, 0x9A, 0x40, 0xD8,
+       0x9F, 0xFC, 0xC0, 0x08, 0xD9, 0x8F, 0xA2, 0xD0,
+       0xC6, 0x84, 0xAB, 0xD0, 0xC2, 0xAF, 0x8A, 0x9B,
+       0x1E, 0xFD, 0x0F, 0x56, 0xFD, 0x0F, 0xA4, 0x8F,
+       0x34, 0xAA, 0x9A, 0x40, 0x84, 0xAB, 0xD0, 0xC4,
+       0xAF, 0x8A, 0x9B, 0x3E, 0xFD, 0x0F, 0x56, 0xFD,
+       0x0F, 0xA4, 0xD0, 0x8F, 0x30, 0xAA, 0x9A, 0x4C,
+       0xD8, 0x9F, 0xFC, 0xC0, 0x0C, 0xD9, 0x8F, 0xA2,
+       0xD0, 0xC7, 0x84, 0xAB, 0xD0, 0xC6, 0xAF, 0x8A,
+       0x9B, 0x1E, 0xFD, 0x0F, 0x76, 0xFD, 0x0F, 0xA4,
+       0xD0, 0x8F, 0x34, 0xAA, 0x9A, 0x40, 0x85, 0xAB,
+       0xD0, 0xC0, 0xAF, 0x8A, 0x9B, 0x3E, 0xFD, 0x0F,
+       0x76, 0xFD, 0x0F, 0xA5, 0x8F, 0x30, 0xAA, 0x9A,
+       0x4C, 0x85, 0xAB, 0xD0, 0xC2, 0xAF, 0x8A, 0x9B,
+       0x5E, 0xFD, 0x0F, 0x76, 0xFD, 0x0F, 0xA5, 0x8F,
+       0x34, 0xAA, 0xD0, 0x9A, 0x50, 0xD8, 0xAF, 0xF8,
+       0xF4, 0x11, 0x99, 0xF1, 0xD8, 0x8B, 0x9C, 0xAF,
+       0x2A, 0xFD, 0x0F, 0x8A, 0x9F, 0xB9, 0xAF, 0x02,
+       0xFD, 0x0F, 0x26, 0xFD, 0x0F, 0x46, 0xFD, 0x0F,
+       0x66, 0xFD, 0x0F, 0x83, 0xB5, 0x9F, 0xBA, 0xA3,
+       0x00, 0x2C, 0x54, 0x7C, 0xB6, 0x82, 0x92, 0xA0,
+       0x31, 0xD9, 0xAD, 0xC3, 0xDA, 0xAD, 0xC5, 0xD8,
+       0x8D, 0xA0, 0x39, 0xDA, 0x82, 0xAD, 0xC7, 0xD8,
+       0xF3, 0x9E, 0xFC, 0xC0, 0x04, 0xD9, 0xF4, 0x0E,
+       0x15, 0xD8, 0xFC, 0xC0, 0x08, 0xD9, 0xF4, 0x0F,
+       0xE4, 0xD8, 0xF1, 0xD8, 0xF1, 0xB9, 0xB1, 0xB5,
+       0xA9, 0xDE, 0xF8, 0x89, 0x99, 0xAF, 0x31, 0xD9,
+       0xF4, 0x13, 0x3F, 0xD8, 0xF1, 0x85, 0xAF, 0x29,
+       /* bank 18: 0x1200 */
+       0xD9, 0x84, 0xA9, 0xC2, 0xD8, 0x85, 0xAF, 0x49,
+       0xD9, 0x84, 0xA9, 0xC4, 0xD8, 0x85, 0xAF, 0x69,
+       0xD9, 0x84, 0xA9, 0xC6, 0xD8, 0x89, 0xAF, 0x39,
+       0xDA, 0x8E, 0xA9, 0x50, 0xF4, 0x13, 0x3F, 0xD8,
+       0xF1, 0x89, 0xAA, 0x7C, 0xFD, 0x02, 0x9A, 0x68,
+       0xD8, 0xF1, 0xAA, 0xFB, 0xDA, 0x89, 0x99, 0xAF,
+       0x26, 0xFD, 0x0F, 0x8F, 0x95, 0x25, 0x89, 0x9F,
+       0xA9, 0x12, 0xFD, 0x0F, 0xF4, 0x13, 0x28, 0xD8,
+       0xF3, 0x9E, 0xFC, 0xC1, 0x04, 0xD9, 0xF4, 0x11,
+       0xF0, 0xD8, 0xFC, 0xC1, 0x08, 0xD9, 0xF4, 0x11,
+       0x0B, 0xD8, 0xF1, 0xBE, 0xBC, 0xBC, 0xBD, 0xBD,
+       0xF7, 0xB8, 0xB4, 0xB0, 0xAC, 0x84, 0x9D, 0x12,
+       0xF9, 0xF2, 0xBC, 0xBC, 0x8A, 0xA7, 0xD0, 0xD9,
+       0xC3, 0xDA, 0xC5, 0xD8, 0xBC, 0xBD, 0xBD, 0xF3,
+       0x8F, 0xA8, 0xC0, 0xF9, 0xAC, 0x84, 0x97, 0xF5,
+       0x1A, 0xF1, 0xF8, 0xF9, 0xD1, 0xDA, 0xA8, 0xDE,
+       0xD8, 0x95, 0xFC, 0xC1, 0x03, 0xD9, 0xA8, 0xDE,
+       0xD8, 0xBC, 0xBC, 0xF1, 0x98, 0xFC, 0xC0, 0x1C,
+       0xDB, 0x95, 0xFC, 0xC0, 0x03, 0xA5, 0xDE, 0xA4,
+       0xDE, 0xD8, 0xAC, 0x88, 0x95, 0x00, 0xD1, 0xD9,
+       0xA5, 0xF8, 0xD8, 0xA4, 0xFC, 0x80, 0x04, 0x88,
+       0x95, 0xA4, 0xFC, 0x08, 0x04, 0x20, 0xF7, 0xBC,
+       0xBD, 0xB5, 0xAC, 0x84, 0x9F, 0xF6, 0x02, 0xF8,
+       0xF9, 0xD1, 0xDB, 0x84, 0x93, 0xF7, 0x6A, 0xF9,
+       0xD9, 0xF3, 0xBC, 0xBC, 0xA8, 0x88, 0x92, 0x18,
+       0xBC, 0xD8, 0xBC, 0xBC, 0xB4, 0xA8, 0x88, 0x9E,
+       0x08, 0xF4, 0xBE, 0xA1, 0xD0, 0xBC, 0xF7, 0xBE,
+       0xBE, 0xB5, 0xAC, 0x84, 0x93, 0x6A, 0xF9, 0xBD,
+       0xBD, 0xB4, 0xD9, 0xF2, 0xAC, 0x8C, 0x97, 0x18,
+       0xF6, 0x84, 0x9C, 0x02, 0xF8, 0xF9, 0xDB, 0xD1,
+       0xF1, 0xA5, 0xDF, 0xD8, 0xF7, 0xBE, 0xBD, 0xA7,
+       0x9D, 0x88, 0x7A, 0xF9, 0xD9, 0xF4, 0x15, 0x8B,
+       /* bank 19: 0x1300 */
+       0xD8, 0xF1, 0xBE, 0xBE, 0xAC, 0xDE, 0xDF, 0xAC,
+       0x88, 0x9F, 0xF7, 0x5A, 0x56, 0xF1, 0xBC, 0xBC,
+       0xBD, 0xBD, 0x95, 0xFC, 0xC0, 0x07, 0xDA, 0xF4,
+       0x15, 0x2C, 0xD8, 0xF1, 0xFC, 0xC0, 0x00, 0xDB,
+       0x9C, 0xFC, 0xC1, 0x00, 0xF4, 0x15, 0x51, 0xD8,
+       0xF1, 0xAC, 0x95, 0xFC, 0xC0, 0x08, 0xDA, 0xF4,
+       0x14, 0x72, 0xD8, 0xF1, 0x82, 0x90, 0x79, 0x2D,
+       0x55, 0xF5, 0x8C, 0x9C, 0x04, 0xAC, 0x2C, 0x54,
+       0xF1, 0xBC, 0xBC, 0x80, 0x5D, 0xDB, 0x49, 0x51,
+       0xF4, 0xBC, 0x14, 0x50, 0xDA, 0xBC, 0x15, 0x28,
+       0xD8, 0xF5, 0x86, 0x98, 0x38, 0xD9, 0xF1, 0x82,
+       0x90, 0x2D, 0xD8, 0xAC, 0xD0, 0x86, 0x98, 0xF5,
+       0x5C, 0xD9, 0xF1, 0x82, 0x90, 0x55, 0xD8, 0xAC,
+       0x8C, 0x9C, 0x00, 0x00, 0xA5, 0xDF, 0xF8, 0xF4,
+       0x14, 0x7D, 0xD8, 0xF1, 0x82, 0x96, 0x2D, 0x55,
+       0x7D, 0x8C, 0x9C, 0x34, 0x18, 0xF1, 0xAC, 0x95,
+       0xF5, 0x1C, 0xD9, 0xF4, 0x15, 0x28, 0xD8, 0xF1,
+       0xAC, 0x83, 0x90, 0x45, 0xD9, 0xA0, 0xF8, 0xAC,
+       0x8C, 0x9C, 0x06, 0xD2, 0xA1, 0x91, 0x00, 0x2C,
+       0x81, 0xD6, 0xF0, 0xA1, 0xD0, 0x8C, 0x9C, 0x28,
+       0xD3, 0x87, 0xD4, 0xA7, 0x8C, 0x20, 0xD3, 0xF1,
+       0xA4, 0x84, 0x90, 0x2C, 0x54, 0x7C, 0xD8, 0xAC,
+       0x83, 0x90, 0x45, 0xD9, 0xF4, 0x15, 0x51, 0xD8,
+       0xF1, 0xAC, 0x81, 0x91, 0x02, 0xFD, 0x18, 0x85,
+       0x66, 0xFD, 0x1F, 0x88, 0x4E, 0xFD, 0x1D, 0x87,
+       0xD4, 0xFD, 0x56, 0xF0, 0x81, 0x9C, 0xAB, 0xD6,
+       0xFD, 0x08, 0x31, 0x8C, 0x10, 0x10, 0x01, 0x01,
+       0x01, 0x39, 0xAC, 0x8B, 0x98, 0xF5, 0x08, 0xD9,
+       0xF4, 0x15, 0x28, 0xD8, 0xF1, 0xA9, 0x82, 0x96,
+       0x01, 0x95, 0xFC, 0xC1, 0x00, 0xDA, 0xF4, 0x15,
+       0x00, 0xDB, 0xF1, 0xAC, 0x89, 0x93, 0xF5, 0x18,
+       0xF1, 0xA5, 0xDF, 0xF8, 0xD8, 0xF4, 0x15, 0x2C,
+       /* bank 20: 0x1400 */
+       0xD8, 0xF1, 0xA4, 0x84, 0x95, 0x34, 0xFD, 0x08,
+       0x54, 0xFD, 0x08, 0x74, 0xFD, 0x08, 0xA9, 0x94,
+       0xF5, 0x2C, 0x54, 0x7C, 0xF1, 0xAC, 0x87, 0x99,
+       0x49, 0xDB, 0x51, 0x59, 0x84, 0xAB, 0xC3, 0xC5,
+       0xC7, 0x82, 0xA6, 0xC0, 0xF3, 0xAA, 0xDF, 0xF8,
+       0xD8, 0xF1, 0xA5, 0xDF, 0xD8, 0xF1, 0xA0, 0xDE,
+       0xA1, 0xDE, 0xDF, 0xDF, 0xDF, 0xA7, 0xDE, 0xDF,
+       0xA4, 0xDF, 0xDF, 0xDF, 0xA2, 0x95, 0xFC, 0xC0,
+       0x01, 0xD9, 0x80, 0xC3, 0xC5, 0xC7, 0xA8, 0x83,
+       0xC1, 0xDA, 0x86, 0xC3, 0xC5, 0xC7, 0xA8, 0x83,
+       0xC3, 0xD8, 0xF1, 0x9A, 0xFC, 0xC1, 0x04, 0xD9,
+       0xAC, 0x82, 0x96, 0x01, 0xF3, 0xAA, 0xDE, 0xF8,
+       0xF8, 0xF8, 0xDB, 0xF5, 0xAC, 0x8C, 0x9A, 0x18,
+       0xF3, 0xAA, 0xF9, 0xD8, 0xAC, 0x8A, 0x9A, 0x41,
+       0xD1, 0xAA, 0xD0, 0xC0, 0xD9, 0xF2, 0xAC, 0x85,
+       0x9A, 0x41, 0xDB, 0xD1, 0xBC, 0xBD, 0xBE, 0xF4,
+       0x15, 0x8B, 0xD8, 0xF3, 0xBC, 0xBD, 0xBE, 0xA5,
+       0x85, 0x9C, 0x10, 0xD8, 0xF1, 0xBB, 0xB2, 0xB6,
+       0xF2, 0xBE, 0xA1, 0xF8, 0xF9, 0xD1, 0xBE, 0xBE,
+       0xBA, 0xDA, 0xA5, 0xDE, 0xD8, 0xA7, 0x82, 0x95,
+       0x65, 0xD1, 0x85, 0xA2, 0xD0, 0xC1, 0xD9, 0xB5,
+       0xA7, 0x86, 0x93, 0x31, 0xDB, 0xD1, 0xF4, 0x15,
+       0xBA, 0xD8, 0xF3, 0xB8, 0xB0, 0xB4, 0xA5, 0x85,
+       0x9C, 0x18, 0xD8, 0xF1, 0xBA, 0xB2, 0xB6, 0x81,
+       0x96, 0xA1, 0xF8, 0xF9, 0xB9, 0xA6, 0xDA, 0xC3,
+       0xC5, 0xC7, 0xD9, 0x2D, 0x4D, 0x6D, 0xD8, 0xBA,
+       0x88, 0xA8, 0xF8, 0xF9, 0xA7, 0xDA, 0xC3, 0xC5,
+       0xC7, 0xD9, 0x2D, 0x4D, 0x6D, 0xD8, 0xF2, 0xB0,
+       0xB9, 0xA3, 0xFA, 0xF9, 0xD1, 0xDA, 0xB8, 0x8F,
+       0xA7, 0xC0, 0xF9, 0xB5, 0x87, 0x93, 0xF6, 0x0A,
+       0xF2, 0xB4, 0xA4, 0x84, 0x97, 0x24, 0xA4, 0x84,
+       0x9E, 0x3C, 0xD8, 0xF7, 0xB9, 0xB0, 0xB5, 0xA6,
+       /* bank 21: 0x1500 */
+       0x88, 0x95, 0x5A, 0xF9, 0xDA, 0xF1, 0xAB, 0xF8,
+       0xD8, 0xB8, 0xB4, 0xF3, 0x98, 0xFC, 0xC0, 0x04,
+       0xDA, 0xF4, 0x16, 0x64, 0xD8, 0xF2, 0xA9, 0xD0,
+       0xF8, 0x89, 0x9B, 0xA7, 0x51, 0xD9, 0xA9, 0xD0,
+       0xDE, 0xA4, 0x84, 0x9E, 0x2C, 0xD8, 0xA8, 0xFA,
+       0x88, 0x9A, 0xA7, 0x29, 0xD9, 0xA8, 0xDF, 0xA4,
+       0x84, 0x9D, 0x34, 0xD8, 0xA8, 0xD0, 0xF8, 0x88,
+       0x9A, 0xA7, 0x51, 0xD9, 0xA8, 0xD0, 0xDE, 0xA4,
+       0x84, 0x9D, 0x2C, 0xD8, 0xA8, 0xD0, 0xFA, 0x88,
+       0x9A, 0xA7, 0x79, 0xD9, 0xA8, 0xD0, 0xDF, 0xA4,
+       0x84, 0x9D, 0x24, 0xD8, 0xF3, 0xA9, 0xD0, 0xF8,
+       0x89, 0x9B, 0xA7, 0x51, 0xD9, 0xA9, 0xD0, 0xDE,
+       0xA4, 0x84, 0x9C, 0x2C, 0xD8, 0xF7, 0xA7, 0x88,
+       0x9F, 0x52, 0xF9, 0xD9, 0xF4, 0x16, 0xA1, 0xD8,
+       0xF1, 0xB9, 0xA2, 0xFA, 0xF3, 0xB8, 0xA9, 0xD0,
+       0xFA, 0x89, 0x9B, 0xA7, 0x79, 0xD9, 0xA9, 0xD0,
+       0xDF, 0xA4, 0x84, 0x9C, 0x24, 0xD8, 0xA7, 0x84,
+       0x9D, 0xF7, 0x12, 0xF9, 0xD9, 0xF4, 0x16, 0xA1,
+       0xD8, 0xF2, 0xA8, 0xD0, 0xF8, 0x88, 0x9A, 0xA7,
+       0x51, 0xD9, 0xA8, 0xD0, 0xDE, 0xA4, 0x84, 0x9D,
+       0x2C, 0xD8, 0xF7, 0xA7, 0x88, 0x9F, 0x42, 0xF9,
+       0xD9, 0xF4, 0x16, 0xE8, 0xD8, 0xF3, 0xA9, 0xF8,
+       0x89, 0x9B, 0xA7, 0x01, 0xD9, 0xA9, 0xDE, 0xA4,
+       0x84, 0x9C, 0x3C, 0xD8, 0xA9, 0xFA, 0x89, 0x9B,
+       0xA7, 0x29, 0xD9, 0xA9, 0xDF, 0xA4, 0x84, 0x9C,
+       0x34, 0xD8, 0xF2, 0xA9, 0xFA, 0x89, 0x9B, 0xA7,
+       0x29, 0xD9, 0xA9, 0xDF, 0xA4, 0x84, 0x9E, 0x34,
+       0xD8, 0xA9, 0xD0, 0xFA, 0x89, 0x9B, 0xA7, 0x79,
+       0xD9, 0xA9, 0xD0, 0xDF, 0xA4, 0x84, 0x9E, 0x24,
+       0xD8, 0xF2, 0xA4, 0x84, 0x9D, 0x3C, 0xF1, 0xA7,
+       0xDE, 0xF2, 0x84, 0xCA, 0x97, 0xA4, 0x24, 0xA5,
+       0x94, 0xF6, 0x0A, 0xF7, 0x85, 0x02, 0xF8, 0xF9,
+       /* bank 22: 0x1600 */
+       0xD1, 0xD9, 0xF6, 0x9B, 0x02, 0xD8, 0xA7, 0xB1,
+       0x80, 0x95, 0x42, 0xF8, 0xF9, 0xD1, 0xD9, 0xF4,
+       0x18, 0x5B, 0xD8, 0xF0, 0xB0, 0x85, 0xA4, 0xD0,
+       0xC0, 0xDD, 0xF2, 0xC0, 0xDC, 0xF6, 0xA7, 0x9F,
+       0x02, 0xF9, 0xD9, 0xF3, 0xA5, 0xDE, 0xDA, 0xF0,
+       0xDD, 0xF2, 0xC8, 0xDC, 0xD8, 0x85, 0x95, 0xA5,
+       0x00, 0xD9, 0x86, 0xF0, 0xDD, 0xF2, 0xCA, 0xCC,
+       0xCE, 0xDC, 0xD8, 0x85, 0x00, 0xD9, 0x80, 0xF0,
+       0xDD, 0xF2, 0xCC, 0xC6, 0xCE, 0xDC, 0xD8, 0x85,
+       0x00, 0xD9, 0xB1, 0x89, 0xF0, 0xDD, 0xF2, 0xC2,
+       0xCA, 0xC4, 0xDC, 0xD8, 0xB0, 0x85, 0x00, 0xD9,
+       0x81, 0xF0, 0xDD, 0xF2, 0xC6, 0xCE, 0x82, 0xC0,
+       0xC8, 0xDC, 0xD8, 0x85, 0x00, 0xB1, 0xD9, 0x86,
+       0xF0, 0xDD, 0xF1, 0xC2, 0xC4, 0xC6, 0xDC, 0xD8,
+       0xB0, 0xF2, 0x85, 0x00, 0xD9, 0xB2, 0x87, 0xF0,
+       0xDD, 0xF1, 0xC2, 0xC4, 0xC6, 0xF2, 0xB2, 0x86,
+       0xC4, 0xDC, 0xD8, 0xB0, 0x85, 0x00, 0xB1, 0xD9,
+       0x8F, 0xF0, 0xDD, 0xF2, 0xC2, 0xC4, 0xC6, 0xDC,
+       0xD8, 0xB0, 0x85, 0x00, 0x00, 0xD9, 0x82, 0xF0,
+       0xDD, 0xF2, 0xC2, 0xCA, 0xC4, 0xDC, 0xD8, 0x85,
+       0x00, 0xD9, 0x85, 0xF0, 0xDD, 0xF1, 0xC2, 0xC4,
+       0xC6, 0xDC, 0xD8, 0xF2, 0x85, 0x00, 0xD9, 0xB1,
+       0x8A, 0xF0, 0xDD, 0xF1, 0xC2, 0xC4, 0xC6, 0xDC,
+       0xD8, 0xB0, 0xF2, 0x85, 0x00, 0xD9, 0xB1, 0xF0,
+       0xDD, 0xF1, 0x82, 0xC4, 0xDC, 0xD8, 0xB0, 0xF3,
+       0xA5, 0xF8, 0xF9, 0xD1, 0xD9, 0xF4, 0x18, 0x10,
+       0xD8, 0xF3, 0x85, 0x95, 0xA5, 0x00, 0x00, 0xD9,
+       0xBE, 0xF2, 0xBA, 0xAE, 0xDE, 0xBE, 0xBE, 0xBC,
+       0xB2, 0x81, 0xF0, 0xDD, 0xF3, 0xC8, 0xDC, 0xBC,
+       0xBC, 0xD8, 0xB0, 0xB8, 0x85, 0xA5, 0x00, 0xD9,
+       0xF2, 0xBE, 0xBE, 0xAA, 0xDE, 0xBE, 0xBC, 0xBC,
+       0x8A, 0xF0, 0xDD, 0xF3, 0xC0, 0xDC, 0xBC, 0xD8,
+       /* bank 23: 0x1700 */
+       0x85, 0xA5, 0x00, 0xD9, 0xB9, 0xF2, 0xA3, 0xD0,
+       0xDE, 0xB2, 0x85, 0xF0, 0xDD, 0xF3, 0xC8, 0xDC,
+       0xD8, 0xF6, 0xB8, 0xB0, 0xA7, 0x84, 0x9D, 0x5A,
+       0xF8, 0xF9, 0xD1, 0xDA, 0xB1, 0x80, 0xF0, 0xDD,
+       0xF3, 0xC4, 0xDC, 0xD8, 0xF2, 0x86, 0xB9, 0xAF,
+       0xC3, 0xC5, 0xC7, 0xF2, 0xB9, 0xA3, 0xDF, 0xB8,
+       0xB0, 0xB4, 0xA7, 0x84, 0x9D, 0xF7, 0x1A, 0xF9,
+       0xD9, 0xF4, 0x18, 0x49, 0xD8, 0xF1, 0xB9, 0xB1,
+       0xB5, 0xA6, 0x83, 0x9B, 0x61, 0xD9, 0xF4, 0x18,
+       0x5B, 0xD8, 0xF6, 0xB8, 0xB0, 0xB4, 0xA7, 0x84,
+       0x94, 0x5A, 0xF8, 0xF9, 0xD1, 0xDA, 0xFE, 0xF1,
+       0xB9, 0xAB, 0xDE, 0xD8, 0xF1, 0xB8, 0xB0, 0xB4,
+       0xA7, 0x88, 0x9C, 0xF7, 0x6A, 0xF9, 0xD9, 0xFF,
+       0xD8, 0xF1, 0xBB, 0xAA, 0xF9, 0xDA, 0xFF, 0xD8,
+       0xB3, 0x8A, 0xC2, 0xB2, 0x8B, 0xB6, 0x94, 0xBA,
+       0xA7, 0x22, 0xB7, 0x93, 0xF0, 0x31, 0x31, 0x20,
+       0xD3, 0x8F, 0xB6, 0x9C, 0xAB, 0x01, 0x29, 0x51,
+       0x79, 0xAF, 0xC2, 0xC5, 0xC7, 0x8B, 0x9B, 0xF1,
+       0x04, 0xFD, 0x01, 0x87, 0xD4, 0x8E, 0x9D, 0xAB,
+       0xF0, 0x01, 0x29, 0x51, 0x79, 0xAE, 0xC2, 0xC5,
+       0xC7, 0x8B, 0x9B, 0xF1, 0x04, 0xFD, 0x01, 0xB3,
+       0x81, 0x94, 0xBB, 0xA7, 0x62, 0xB7, 0x93, 0xF0,
+       0x71, 0x71, 0x60, 0x85, 0x94, 0x01, 0x29, 0x51,
+       0x79, 0xA5, 0xC2, 0xC5, 0xC7, 0x87, 0x97, 0xF1,
+       0x04, 0xFD, 0x01, 0x81, 0xB6, 0x94, 0xA7, 0x02,
+       0xB7, 0x93, 0xF0, 0x11, 0x11, 0x00, 0x8E, 0x9B,
+       0x01, 0x29, 0x51, 0x79, 0xAE, 0xC2, 0xC5, 0xC7,
+       0x87, 0x97, 0xF1, 0x04, 0xFD, 0x01, 0x83, 0xA3,
+       0xC2, 0xC5, 0xC7, 0xB2, 0x84, 0xC1, 0xB0, 0xB4,
+       0xB8, 0x88, 0x9D, 0xA7, 0xF7, 0x62, 0xF9, 0xD9,
+       0xF4, 0x19, 0x5E, 0xD8, 0xF1, 0xBE, 0xAA, 0xF8,
+       0xFA, 0xAB, 0xDE, 0xBC, 0x8B, 0xBD, 0x9B, 0xBE,
+       /* bank 24: 0x1800 */
+       0xBE, 0xBA, 0xAF, 0xD0, 0xFC, 0x58, 0x00, 0x10,
+       0xBE, 0xB8, 0xFC, 0xC0, 0x04, 0xDB, 0xFC, 0xC1,
+       0x00, 0xAA, 0xDE, 0xDF, 0xAC, 0xDE, 0xDF, 0xAB,
+       0xDF, 0xF8, 0xD8, 0xAC, 0xFC, 0x90, 0x00, 0x8C,
+       0xFC, 0x09, 0x04, 0x00, 0x8A, 0x9C, 0xA9, 0x31,
+       0xD9, 0xAA, 0xDF, 0xAC, 0xDF, 0xD8, 0x9B, 0xFC,
+       0xC0, 0x04, 0xDB, 0x9A, 0xA9, 0x19, 0xAC, 0xF8,
+       0xD8, 0x9B, 0xFC, 0xC1, 0x04, 0xDB, 0x9A, 0xA9,
+       0x11, 0xAB, 0xDF, 0x8C, 0x9C, 0xA9, 0x19, 0xD9,
+       0xF3, 0xBC, 0xBC, 0xBD, 0xBD, 0xBE, 0xBE, 0x8D,
+       0x94, 0xA4, 0xD0, 0x1D, 0xF4, 0x42, 0xDA, 0xF1,
+       0xBC, 0xBC, 0xBD, 0xBD, 0xBE, 0xBE, 0xD8, 0xF1,
+       0xB1, 0x8B, 0xB5, 0x9A, 0xB9, 0xA6, 0x41, 0xD9,
+       0xAA, 0xF8, 0xF5, 0xB2, 0x8F, 0xB6, 0x9F, 0xA6,
+       0x78, 0x8E, 0x9E, 0x7C, 0xF1, 0xB1, 0x81, 0xB5,
+       0x96, 0x05, 0x2D, 0x8E, 0xA6, 0x72, 0x7E, 0x81,
+       0xA1, 0x00, 0x2C, 0xF4, 0x19, 0xAA, 0xD8, 0xF1,
+       0xAA, 0xDE, 0x81, 0x91, 0xA6, 0x2C, 0xFD, 0x02,
+       0x96, 0x29, 0x92, 0xFC, 0xC0, 0x03, 0xD9, 0x96,
+       0x29, 0xD8, 0xA2, 0xDE, 0xF8, 0x86, 0x91, 0xA6,
+       0x21, 0xDB, 0x8B, 0x61, 0xA2, 0xDE, 0xB3, 0x86,
+       0xA4, 0xC0, 0xD8, 0xF3, 0xBB, 0xB3, 0xB7, 0xA2,
+       0xF8, 0xF2, 0xF8, 0xF1, 0x80, 0x9D, 0xAD, 0xD0,
+       0x7C, 0xF2, 0xA2, 0xFA, 0xF9, 0xD1, 0xF1, 0xB9,
+       0xAC, 0xD9, 0xDE, 0xDA, 0xF8, 0xD8, 0xF2, 0xA6,
+       0x82, 0x92, 0x49, 0xF9, 0xDB, 0xF1, 0xB1, 0x8C,
+       0xB5, 0x9C, 0x21, 0xD9, 0xF5, 0xB3, 0x85, 0xB7,
+       0x95, 0x78, 0x8E, 0x9E, 0x7C, 0xF1, 0xB1, 0x8D,
+       0xB5, 0x9D, 0xAD, 0x1A, 0xF0, 0x96, 0x40, 0x9D,
+       0x3C, 0x96, 0x48, 0xD8, 0xF1, 0xB1, 0x8E, 0xB5,
+       0x9D, 0xB9, 0xA6, 0x2A, 0x8D, 0x96, 0x05, 0xD9,
+       0xF4, 0x1A, 0x23, 0xD8, 0xF2, 0xB3, 0x82, 0xB7,
+       /* bank 25: 0x1900 */
+       0x92, 0xBB, 0xAF, 0x49, 0xF9, 0xF9, 0xDB, 0xF1,
+       0xB1, 0x8C, 0xB5, 0x9C, 0xB9, 0xA6, 0x21, 0xF4,
+       0x1A, 0x23, 0xD8, 0xF1, 0xB3, 0x8E, 0xBB, 0xA8,
+       0xD0, 0xC4, 0xC7, 0xF3, 0xB9, 0xAC, 0xD0, 0xDE,
+       0xF4, 0x1A, 0x34, 0xD8, 0xF1, 0xB3, 0x85, 0xBB,
+       0xA8, 0xD0, 0xC4, 0xC7, 0xF3, 0xB9, 0xAC, 0xD0,
+       0xDE, 0xF8, 0xDF, 0xF8, 0xD8, 0xF3, 0xB5, 0x9C,
+       0xFC, 0xC3, 0x04, 0xDB, 0xFC, 0xC2, 0x00, 0xD9,
+       0xF2, 0xAC, 0xD0, 0xDE, 0xD8, 0xF2, 0xBB, 0xAF,
+       0xB7, 0x92, 0xB3, 0x82, 0x19, 0x80, 0xA2, 0xD9,
+       0x26, 0xF3, 0xA7, 0xD0, 0xDF, 0xD8, 0xF1, 0xAF,
+       0x89, 0x98, 0x19, 0xA9, 0x80, 0xD9, 0x38, 0xD8,
+       0xAF, 0x89, 0x39, 0xA9, 0x80, 0xDA, 0x3C, 0xD8,
+       0xAF, 0x2E, 0x88, 0xF5, 0x75, 0xDA, 0xFF, 0xD8,
+       0x71, 0xDA, 0xF1, 0xFF, 0xD8, 0x82, 0xA7, 0xF3,
+       0xC1, 0xF2, 0x80, 0xC2, 0xF1, 0x97, 0x86, 0x49,
+       0x2E, 0xA6, 0xD0, 0x50, 0x96, 0x86, 0xAF, 0x75,
+       0xD9, 0x88, 0xA2, 0xD0, 0xF3, 0xC0, 0xC3, 0xF1,
+       0xDA, 0x8F, 0x96, 0xA2, 0xD0, 0xF3, 0xC2, 0xC3,
+       0x82, 0xB6, 0x9B, 0x78, 0x78, 0xF1, 0xD8, 0xB7,
+       0xAF, 0xDF, 0xF9, 0x89, 0x99, 0xAF, 0x10, 0x80,
+       0x9F, 0x21, 0xDA, 0x2E, 0xD8, 0x89, 0x99, 0xAF,
+       0x31, 0xDA, 0xDF, 0xD8, 0xAF, 0x82, 0x92, 0xF3,
+       0x41, 0xD9, 0xF1, 0xDF, 0xD8, 0xAF, 0x82, 0xF3,
+       0x19, 0xD9, 0xF1, 0xDF, 0xD8, 0xF1, 0x89, 0x90,
+       0xAF, 0xD0, 0x09, 0x8F, 0x99, 0xAF, 0x51, 0xDB,
+       0x89, 0x31, 0xF3, 0x82, 0x92, 0x19, 0xF2, 0xB1,
+       0x8C, 0xB5, 0x9C, 0x71, 0xD9, 0xF1, 0xDF, 0xF9,
+       0xF2, 0xB9, 0xAC, 0xD0, 0xF8, 0xF8, 0xF3, 0xDF,
+       0xD8, 0xB3, 0xB7, 0xBB, 0x82, 0xAC, 0xF3, 0xC0,
+       0xA2, 0x80, 0x22, 0xF1, 0xA9, 0x22, 0x26, 0x9F,
+       0xAF, 0x29, 0xDA, 0xAC, 0xDE, 0xFF, 0xD8, 0xA2,
+       /* bank 26: 0x1A00 */
+       0xF2, 0xDE, 0xF1, 0xA9, 0xDF, 0xB5, 0x92, 0xFC,
+       0xC0, 0x00, 0xD9, 0xFF, 0xD8, 0xAD, 0xD0, 0xDE,
+       0xF8, 0xB1, 0x84, 0xB6, 0x96, 0xBA, 0xA7, 0xD0,
+       0x7E, 0xB7, 0x96, 0xA7, 0x01, 0xB2, 0x87, 0x9D,
+       0x05, 0xDB, 0xB3, 0x8D, 0xB6, 0x97, 0x79, 0xF3,
+       0xB1, 0x8C, 0x96, 0x49, 0xF1, 0xBB, 0xAD, 0xD0,
+       0xF8, 0xD8, 0xF3, 0xB9, 0xAC, 0xD0, 0xF8, 0xF9,
+       0xD1, 0xD9, 0xF1, 0xBB, 0xAD, 0xD0, 0xF8, 0xD8,
+       0xB3, 0xB7, 0xBB, 0x97, 0x8C, 0xAF, 0xF3, 0x79,
+       0xD9, 0xF4, 0x1B, 0x6D, 0xD8, 0xF1, 0xB1, 0x82,
+       0xB9, 0xA2, 0xD0, 0xC2, 0xB3, 0xF2, 0xB9, 0xA3,
+       0xFA, 0xF1, 0xBB, 0xAA, 0xD0, 0xF8, 0xB8, 0xB0,
+       0xB4, 0xA7, 0x88, 0x9C, 0xF7, 0x72, 0xF9, 0xF4,
+       0xDA, 0x44, 0xD8, 0x1B, 0x80, 0xD8, 0xF3, 0xB3,
+       0xB7, 0xBB, 0xA7, 0xD0, 0xFA, 0x97, 0x8C, 0xAF,
+       0x79, 0xDA, 0xF1, 0x87, 0x9A, 0xAA, 0xD0, 0x70,
+       0xD8, 0xF2, 0xBB, 0xB3, 0xB7, 0x82, 0x92, 0xAF,
+       0x31, 0xDA, 0xF4, 0x1B, 0xBD, 0xD8, 0xF1, 0x8D,
+       0x96, 0xA6, 0x40, 0xAC, 0x8C, 0x9C, 0x0C, 0x30,
+       0xBA, 0x8D, 0x9D, 0xA7, 0x39, 0xDB, 0xF3, 0xB1,
+       0x8C, 0xB6, 0x96, 0x49, 0xD9, 0xF1, 0x84, 0xB5,
+       0x94, 0xB9, 0xA4, 0xD0, 0x5E, 0xF0, 0xB7, 0x9D,
+       0x38, 0xD8, 0xF1, 0xBB, 0xAC, 0xDE, 0xD0, 0xDE,
+       0xAD, 0xD0, 0xDF, 0xF1, 0xFF, 0xD8, 0xF3, 0xB9,
+       0xAC, 0xD0, 0xF8, 0xF9, 0xD1, 0xD9, 0xF2, 0xBB,
+       0xA2, 0xFA, 0xF8, 0xDA, 0xF2, 0xBB, 0xA2, 0xFA,
+       0xD8, 0xF2, 0xBB, 0x82, 0xAF, 0xC2, 0xF9, 0xD1,
+       0xD9, 0xF1, 0xB9, 0xAC, 0xDE, 0xAD, 0xDE, 0xDF,
+       0xD8, 0xF1, 0x8C, 0x9C, 0xBB, 0xAC, 0xD0, 0x10,
+       0xAC, 0xDE, 0xAD, 0xD0, 0xDF, 0x92, 0x82, 0xAF,
+       0xF1, 0xCA, 0xF2, 0x35, 0xF1, 0x96, 0x8F, 0xA6,
+       0xD9, 0x00, 0xD8, 0xF1, 0xFF,
+       /* bank 27: 0x1B00 */
+};
 #endif /* ICM_DMP_FW_VER */
 
 struct nvi_dmp nvi_dmp_icm = {
@@ -2930,6 +4051,7 @@ struct nvi_dmp nvi_dmp_icm = {
        .fw_mem_addr                    = 0x90,
        .fw_start                       = 0x08D0,
        .dmp_reset_delay_ms             = 25,
+       .fifo_mode                      = ICM_DMP_FIFO_MODE,
        .dev_msk                        = ICM_DMP_DEV_MSK,
        .en_msk                         = MSK_DEV_ALL,
        .dd_n                           = ARRAY_SIZE(nvi_dmp_devs),
index 1cc205d..0dc0329 100644 (file)
 
 /* Invensense doesn't label their DMP FW with a version so we use
  * ICM_DMP_FW_VER sequentially starting at 0.
- * Currently a version 0 or 1 is the option here as both are included in this
- * driver.  Typically version 0 would be used although 1 is the latest.
+ * Currently a version 0, 1 or 2 is the option here as all are included in
+ * this driver.  Version 2 is recommended that includes timing fixes.
  */
-#define ICM_DMP_FW_VER                 (0)
+#define ICM_DMP_FW_VER                 (2)
 #if ICM_DMP_FW_VER == 0
 #define ICM_DMP_FW_CRC32               (0x12F362A6)
-#else
+#define ICM_DMP_FIFO_MODE              (0)
+#define ICM_SMD_TIMER_THLD_INIT                (0x00000258)
+#elif ICM_DMP_FW_VER == 1
 #define ICM_DMP_FW_CRC32               (0xFEF1270D)
+#define ICM_DMP_FIFO_MODE              (0)
+#define ICM_SMD_TIMER_THLD_INIT                (0x0000015E)
+#else /* ICM_DMP_FW_VER == 2 */
+#define ICM_DMP_FW_CRC32               (0xDA126847)
+#define ICM_DMP_FIFO_MODE              (-1)
+#define ICM_SMD_TIMER_THLD_INIT                (0x0000015E)
 #endif /* ICM_DMP_FW_VER */
 
 #define ICM_DMP_FREQ                   (102)
 #define ICM_DMP_PERIOD_US              (9804)
 #define ICM_BASE_SAMPLE_RATE           (1125)
 #define ICM_DMP_DIVIDER                        (ICM_BASE_SAMPLE_RATE / ICM_DMP_FREQ)
-#define ICM_SMD_TIMER_THLD_INIT                (0x0000015E)
 
 #define DATA_OUT_CTL1                  (4 * 16)        /* 0x0040 */
 #define DATA_OUT_CTL2                  (4 * 16 + 2)    /* 0x0042 */
 #define PEDSTD_DRIVE_STATE             (43 * 16 + 10)
 #define PED_RATE                       (58 * 16 +  4)  /* 0x03A4 */
 
+/* FW verison 0 */
 #define SMD_MOT_THLD                   (72 * 16 + 12)  /* 0x048C */
 #define SMD_DELAY_THLD                 (76 * 16 + 8)   /* 0x04C8 */
 #define SMD_DELAY2_THLD                        (76 * 16 + 12)  /* 0x04CC */
-
+/* FW version 1 */
 #define SMD_TIMER_THLD                 (26 * 16)       /* 0x01A0 */
+/* FW version 2 */
+#define SMD_E1_THLD                    (75 * 16 +  8)  /* 0x04B8 */
+#define SMD_CNTR_TH                    (74 * 16 +  8)  /* 0x04A8 */
+#define SMD_CNTR_LO_TH                 (74 * 16 + 12)  /* 0x04AC */
+#define SMD_LOW_ENERGY_TIMER_TH                (76 * 16 +  8)  /* 0x04C8 */
+#define SMD_E1_COUNTER_TH              (76 * 16 + 12)  /* 0x04CC */
 
 #define WOM_ENABLE                     (64 * 16 + 14)  /* 0x040E */
 #define WOM_STATUS                     (64 * 16 + 6)   /* 0x0406 */
 #define TILT_ENABLE                    (68 * 16 + 12)
 #define BAC_STATE                      (147 * 16)
 
-#define ACCEL_MASK                     0x80
-#define GYRO_MASK                      0x40
-#define CPASS_MASK                     0x20
-#define ALS_MASK                       0x10
-#define QUAT6_MASK                     0x08
-#define QUAT9_MASK                     0x04
-#define PQUAT6_MASK                    0x02
-#define PRESSURE_MASK                  0x80
-#define GYRO_CALIBR_MASK               0x40
-#define CPASS_CALIBR_MASK              0x20
-#define PED_STEPDET_MASK               0x10
-#define HEADER2_MASK                   0x08
-#define PED_STEPIND_MASK               0x07
+#define ACC_SCALE                      (30 * 16 + 0)   /* 0x01E0 */
+#define ACC_SCALE2                     (79 * 16 + 4)   /* 0x04F4 */
 
 #define ACCEL_SET                      0x8000
 #define GYRO_SET                       0x4000
 #define HEADER2_SET                    0x0008
 #define PED_STEPIND_SET                        0x0007
 
-#define ACCEL_ACCURACY_MASK            0x4000
-#define GYRO_ACCURACY_MASK             0x2000
-#define CPASS_ACCURACY_MASK            0x1000
-#define GEOMAG_MASK                    0x0200
-#define BATCH_MODE_MASK                        0x0100
-#define ACT_RECOG_MASK                 0x8000
-
 #define ACCEL_ACCURACY_SET             0x4000
 #define GYRO_ACCURACY_SET              0x2000
 #define CPASS_ACCURACY_SET             0x1000
index 9aa7f43..044db1b 100644 (file)
@@ -405,8 +405,8 @@ static int inv_icm_st_acc_do(struct nvi_state *st,
        }
        accel_s = 0;
        ret = inv_icm_st_rd(st, DEV_ACC, accel_result, &accel_s);
-       if (ret)
-               return ret;
+       if (ret || accel_s <= 0)
+               return -1;
 
        for (j = 0; j < AXIS_N; j++) {
                accel_result[j] = accel_result[j] / accel_s;
@@ -422,8 +422,8 @@ static int inv_icm_st_acc_do(struct nvi_state *st,
        msleep(ICM_ST_STABLE_TIME);
        accel_s = 0;
        ret = inv_icm_st_rd(st, DEV_ACC, accel_st_result, &accel_s);
-       if (ret)
-               return ret;
+       if (ret || accel_s <= 0)
+               return -1;
 
        for (j = 0; j < AXIS_N; j++) {
                accel_st_result[j] = accel_st_result[j] / accel_s;
@@ -453,8 +453,8 @@ static int inv_icm_st_gyr_do(struct nvi_state *st,
        }
        gyro_s = 0;
        ret = inv_icm_st_rd(st, DEV_GYR, gyro_result, &gyro_s);
-       if (ret)
-               return ret;
+       if (ret || gyro_s <= 0)
+               return -1;
 
        for (j = 0; j < AXIS_N; j++) {
                gyro_result[j] = gyro_result[j] / gyro_s;
@@ -470,8 +470,8 @@ static int inv_icm_st_gyr_do(struct nvi_state *st,
        msleep(ICM_ST_STABLE_TIME);
        gyro_s = 0;
        ret = inv_icm_st_rd(st, DEV_GYR, gyro_st_result, &gyro_s);
-       if (ret)
-               return ret;
+       if (ret || gyro_s <= 0)
+               return -1;
 
        for (j = 0; j < AXIS_N; j++) {
                gyro_st_result[j] = gyro_st_result[j] / gyro_s;
@@ -628,9 +628,7 @@ static int nvi_init_icm(struct nvi_state *st)
        int ret;
 
        st->snsr[DEV_ACC].cfg.thresh_hi = 0; /* no ACC LP on ICM */
-#if ICM_DMP_FW_VER == 1
        st->snsr[DEV_SM].cfg.thresh_hi = ICM_SMD_TIMER_THLD_INIT;
-#endif /* ICM_DMP_FW_VER */
        ret = nvi_i2c_rd(st, &st->hal->reg->tbc_pll, &val);
        if (ret)
                return ret;
@@ -650,16 +648,7 @@ static int nvi_init_icm(struct nvi_state *st)
        return 0;
 }
 
-static void nvi_por2rc_icm(struct nvi_state *st)
-{
-       st->rc.lp_config = 0x40;
-       st->rc.pm1 = 0x41;
-       st->rc.gyro_config1 = 0x01;
-       st->rc.accel_config = 0x01;
-}
-
 struct nvi_fn nvi_fn_icm = {
-       .por2rc                         = nvi_por2rc_icm,
        .pm                             = nvi_pm_icm,
        .init                           = nvi_init_icm,
        .st_acc                         = inv_st_acc_icm,