static void omap_prcm_write(void *opaque, target_phys_addr_t addr,

                            uint64_t value, unsigned size)

{

    struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;



    if (size != 4) {

        return omap_badwidth_write32(opaque, addr, value);

    }



    switch (addr) {

    case 0x000:	/* PRCM_REVISION */

    case 0x054:	/* PRCM_VOLTST */

    case 0x084:	/* PRCM_CLKCFG_STATUS */

    case 0x1e4:	/* PM_PWSTST_MPU */

    case 0x220:	/* CM_IDLEST1_CORE */

    case 0x224:	/* CM_IDLEST2_CORE */

    case 0x22c:	/* CM_IDLEST4_CORE */

    case 0x2c8:	/* PM_WKDEP_CORE */

    case 0x2e4:	/* PM_PWSTST_CORE */

    case 0x320:	/* CM_IDLEST_GFX */

    case 0x3e4:	/* PM_PWSTST_GFX */

    case 0x420:	/* CM_IDLEST_WKUP */

    case 0x520:	/* CM_IDLEST_CKGEN */

    case 0x820:	/* CM_IDLEST_DSP */

    case 0x8e4:	/* PM_PWSTST_DSP */

        OMAP_RO_REG(addr);

        return;



    case 0x010:	/* PRCM_SYSCONFIG */

        s->sysconfig = value & 1;

        break;



    case 0x018:	/* PRCM_IRQSTATUS_MPU */

        s->irqst[0] &= ~value;

        omap_prcm_int_update(s, 0);

        break;

    case 0x01c:	/* PRCM_IRQENABLE_MPU */

        s->irqen[0] = value & 0x3f;

        omap_prcm_int_update(s, 0);

        break;



    case 0x050:	/* PRCM_VOLTCTRL */

        s->voltctrl = value & 0xf1c3;

        break;



    case 0x060:	/* PRCM_CLKSRC_CTRL */

        s->clksrc[0] = value & 0xdb;

        /* TODO update clocks */

        break;



    case 0x070:	/* PRCM_CLKOUT_CTRL */

        s->clkout[0] = value & 0xbbbb;

        /* TODO update clocks */

        break;



    case 0x078:	/* PRCM_CLKEMUL_CTRL */

        s->clkemul[0] = value & 1;

        /* TODO update clocks */

        break;



    case 0x080:	/* PRCM_CLKCFG_CTRL */

        break;



    case 0x090:	/* PRCM_VOLTSETUP */

        s->setuptime[0] = value & 0xffff;

        break;

    case 0x094:	/* PRCM_CLKSSETUP */

        s->setuptime[1] = value & 0xffff;

        break;



    case 0x098:	/* PRCM_POLCTRL */

        s->clkpol[0] = value & 0x701;

        break;



    case 0x0b0:	/* GENERAL_PURPOSE1 */

    case 0x0b4:	/* GENERAL_PURPOSE2 */

    case 0x0b8:	/* GENERAL_PURPOSE3 */

    case 0x0bc:	/* GENERAL_PURPOSE4 */

    case 0x0c0:	/* GENERAL_PURPOSE5 */

    case 0x0c4:	/* GENERAL_PURPOSE6 */

    case 0x0c8:	/* GENERAL_PURPOSE7 */

    case 0x0cc:	/* GENERAL_PURPOSE8 */

    case 0x0d0:	/* GENERAL_PURPOSE9 */

    case 0x0d4:	/* GENERAL_PURPOSE10 */

    case 0x0d8:	/* GENERAL_PURPOSE11 */

    case 0x0dc:	/* GENERAL_PURPOSE12 */

    case 0x0e0:	/* GENERAL_PURPOSE13 */

    case 0x0e4:	/* GENERAL_PURPOSE14 */

    case 0x0e8:	/* GENERAL_PURPOSE15 */

    case 0x0ec:	/* GENERAL_PURPOSE16 */

    case 0x0f0:	/* GENERAL_PURPOSE17 */

    case 0x0f4:	/* GENERAL_PURPOSE18 */

    case 0x0f8:	/* GENERAL_PURPOSE19 */

    case 0x0fc:	/* GENERAL_PURPOSE20 */

        s->scratch[(addr - 0xb0) >> 2] = value;

        break;



    case 0x140:	/* CM_CLKSEL_MPU */

        s->clksel[0] = value & 0x1f;

        /* TODO update clocks */

        break;

    case 0x148:	/* CM_CLKSTCTRL_MPU */

        s->clkctrl[0] = value & 0x1f;

        break;



    case 0x158:	/* RM_RSTST_MPU */

        s->rst[0] &= ~value;

        break;

    case 0x1c8:	/* PM_WKDEP_MPU */

        s->wkup[0] = value & 0x15;

        break;



    case 0x1d4:	/* PM_EVGENCTRL_MPU */

        s->ev = value & 0x1f;

        break;

    case 0x1d8:	/* PM_EVEGENONTIM_MPU */

        s->evtime[0] = value;

        break;

    case 0x1dc:	/* PM_EVEGENOFFTIM_MPU */

        s->evtime[1] = value;

        break;



    case 0x1e0:	/* PM_PWSTCTRL_MPU */

        s->power[0] = value & 0xc0f;

        break;



    case 0x200:	/* CM_FCLKEN1_CORE */

        s->clken[0] = value & 0xbfffffff;

        /* TODO update clocks */

        /* The EN_EAC bit only gets/puts func_96m_clk.  */

        break;

    case 0x204:	/* CM_FCLKEN2_CORE */

        s->clken[1] = value & 0x00000007;

        /* TODO update clocks */

        break;

    case 0x210:	/* CM_ICLKEN1_CORE */

        s->clken[2] = value & 0xfffffff9;

        /* TODO update clocks */

        /* The EN_EAC bit only gets/puts core_l4_iclk.  */

        break;

    case 0x214:	/* CM_ICLKEN2_CORE */

        s->clken[3] = value & 0x00000007;

        /* TODO update clocks */

        break;

    case 0x21c:	/* CM_ICLKEN4_CORE */

        s->clken[4] = value & 0x0000001f;

        /* TODO update clocks */

        break;



    case 0x230:	/* CM_AUTOIDLE1_CORE */

        s->clkidle[0] = value & 0xfffffff9;

        /* TODO update clocks */

        break;

    case 0x234:	/* CM_AUTOIDLE2_CORE */

        s->clkidle[1] = value & 0x00000007;

        /* TODO update clocks */

        break;

    case 0x238:	/* CM_AUTOIDLE3_CORE */

        s->clkidle[2] = value & 0x00000007;

        /* TODO update clocks */

        break;

    case 0x23c:	/* CM_AUTOIDLE4_CORE */

        s->clkidle[3] = value & 0x0000001f;

        /* TODO update clocks */

        break;



    case 0x240:	/* CM_CLKSEL1_CORE */

        s->clksel[1] = value & 0x0fffbf7f;

        /* TODO update clocks */

        break;



    case 0x244:	/* CM_CLKSEL2_CORE */

        s->clksel[2] = value & 0x00fffffc;

        /* TODO update clocks */

        break;



    case 0x248:	/* CM_CLKSTCTRL_CORE */

        s->clkctrl[1] = value & 0x7;

        break;



    case 0x2a0:	/* PM_WKEN1_CORE */

        s->wken[0] = value & 0x04667ff8;

        break;

    case 0x2a4:	/* PM_WKEN2_CORE */

        s->wken[1] = value & 0x00000005;

        break;



    case 0x2b0:	/* PM_WKST1_CORE */

        s->wkst[0] &= ~value;

        break;

    case 0x2b4:	/* PM_WKST2_CORE */

        s->wkst[1] &= ~value;

        break;



    case 0x2e0:	/* PM_PWSTCTRL_CORE */

        s->power[1] = (value & 0x00fc3f) | (1 << 2);

        break;



    case 0x300:	/* CM_FCLKEN_GFX */

        s->clken[5] = value & 6;

        /* TODO update clocks */

        break;

    case 0x310:	/* CM_ICLKEN_GFX */

        s->clken[6] = value & 1;

        /* TODO update clocks */

        break;

    case 0x340:	/* CM_CLKSEL_GFX */

        s->clksel[3] = value & 7;

        /* TODO update clocks */

        break;

    case 0x348:	/* CM_CLKSTCTRL_GFX */

        s->clkctrl[2] = value & 1;

        break;

    case 0x350:	/* RM_RSTCTRL_GFX */

        s->rstctrl[0] = value & 1;

        /* TODO: reset */

        break;

    case 0x358:	/* RM_RSTST_GFX */

        s->rst[1] &= ~value;

        break;

    case 0x3c8:	/* PM_WKDEP_GFX */

        s->wkup[1] = value & 0x13;

        break;

    case 0x3e0:	/* PM_PWSTCTRL_GFX */

        s->power[2] = (value & 0x00c0f) | (3 << 2);

        break;



    case 0x400:	/* CM_FCLKEN_WKUP */

        s->clken[7] = value & 0xd;

        /* TODO update clocks */

        break;

    case 0x410:	/* CM_ICLKEN_WKUP */

        s->clken[8] = value & 0x3f;

        /* TODO update clocks */

        break;

    case 0x430:	/* CM_AUTOIDLE_WKUP */

        s->clkidle[4] = value & 0x0000003f;

        /* TODO update clocks */

        break;

    case 0x440:	/* CM_CLKSEL_WKUP */

        s->clksel[4] = value & 3;

        /* TODO update clocks */

        break;

    case 0x450:	/* RM_RSTCTRL_WKUP */

        /* TODO: reset */

        if (value & 2)

            qemu_system_reset_request();

        break;

    case 0x454:	/* RM_RSTTIME_WKUP */

        s->rsttime_wkup = value & 0x1fff;

        break;

    case 0x458:	/* RM_RSTST_WKUP */

        s->rst[2] &= ~value;

        break;

    case 0x4a0:	/* PM_WKEN_WKUP */

        s->wken[2] = value & 0x00000005;

        break;

    case 0x4b0:	/* PM_WKST_WKUP */

        s->wkst[2] &= ~value;

        break;



    case 0x500:	/* CM_CLKEN_PLL */

        if (value & 0xffffff30)

            fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for "

                            "future compatibility\n", __FUNCTION__);

        if ((s->clken[9] ^ value) & 0xcc) {

            s->clken[9] &= ~0xcc;

            s->clken[9] |= value & 0xcc;

            omap_prcm_apll_update(s);

        }

        if ((s->clken[9] ^ value) & 3) {

            s->clken[9] &= ~3;

            s->clken[9] |= value & 3;

            omap_prcm_dpll_update(s);

        }

        break;

    case 0x530:	/* CM_AUTOIDLE_PLL */

        s->clkidle[5] = value & 0x000000cf;

        /* TODO update clocks */

        break;

    case 0x540:	/* CM_CLKSEL1_PLL */

        if (value & 0xfc4000d7)

            fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for "

                            "future compatibility\n", __FUNCTION__);

        if ((s->clksel[5] ^ value) & 0x003fff00) {

            s->clksel[5] = value & 0x03bfff28;

            omap_prcm_dpll_update(s);

        }

        /* TODO update the other clocks */



        s->clksel[5] = value & 0x03bfff28;

        break;

    case 0x544:	/* CM_CLKSEL2_PLL */

        if (value & ~3)

            fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for "

                            "future compatibility\n", __FUNCTION__);

        if (s->clksel[6] != (value & 3)) {

            s->clksel[6] = value & 3;

            omap_prcm_dpll_update(s);

        }

        break;



    case 0x800:	/* CM_FCLKEN_DSP */

        s->clken[10] = value & 0x501;

        /* TODO update clocks */

        break;

    case 0x810:	/* CM_ICLKEN_DSP */

        s->clken[11] = value & 0x2;

        /* TODO update clocks */

        break;

    case 0x830:	/* CM_AUTOIDLE_DSP */

        s->clkidle[6] = value & 0x2;

        /* TODO update clocks */

        break;

    case 0x840:	/* CM_CLKSEL_DSP */

        s->clksel[7] = value & 0x3fff;

        /* TODO update clocks */

        break;

    case 0x848:	/* CM_CLKSTCTRL_DSP */

        s->clkctrl[3] = value & 0x101;

        break;

    case 0x850:	/* RM_RSTCTRL_DSP */

        /* TODO: reset */

        break;

    case 0x858:	/* RM_RSTST_DSP */

        s->rst[3] &= ~value;

        break;

    case 0x8c8:	/* PM_WKDEP_DSP */

        s->wkup[2] = value & 0x13;

        break;

    case 0x8e0:	/* PM_PWSTCTRL_DSP */

        s->power[3] = (value & 0x03017) | (3 << 2);

        break;



    case 0x8f0:	/* PRCM_IRQSTATUS_DSP */

        s->irqst[1] &= ~value;

        omap_prcm_int_update(s, 1);

        break;

    case 0x8f4:	/* PRCM_IRQENABLE_DSP */

        s->irqen[1] = value & 0x7;

        omap_prcm_int_update(s, 1);

        break;



    case 0x8f8:	/* PRCM_IRQSTATUS_IVA */

        s->irqst[2] &= ~value;

        omap_prcm_int_update(s, 2);

        break;

    case 0x8fc:	/* PRCM_IRQENABLE_IVA */

        s->irqen[2] = value & 0x7;

        omap_prcm_int_update(s, 2);

        break;



    default:

        OMAP_BAD_REG(addr);

        return;

    }

}
