Implement power state changes (IDLE and SLEEP) for PXA.
authorbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 1 May 2007 01:28:01 +0000 (01:28 +0000)
committerbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>
Tue, 1 May 2007 01:28:01 +0000 (01:28 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2762 c046a42c-6fe2-441c-8c8c-71466251a162

cpu-all.h
cpu-exec.c
hw/pxa2xx.c
target-arm/translate.c

index db1e947fec9ba5278aee169ffc3c7bf26bcab91a..0aa38435400382188342fd431042b46e2cc267f2 100644 (file)
--- a/cpu-all.h
+++ b/cpu-all.h
@@ -772,7 +772,8 @@ void cpu_dump_statistics (CPUState *env, FILE *f,
                           int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
                           int flags);
 
-void cpu_abort(CPUState *env, const char *fmt, ...);
+void cpu_abort(CPUState *env, const char *fmt, ...)
+    __attribute__ ((__format__ (__printf__, 2, 3)));
 extern CPUState *first_cpu;
 extern CPUState *cpu_single_env;
 extern int code_copy_enabled;
index 284cb92ae83a2a36e05137d3532106ff85167364..4777babd2a081642909c6cdae5d52f00418f1730 100644 (file)
@@ -279,9 +279,10 @@ int cpu_exec(CPUState *env1)
 #elif defined(TARGET_ARM)
     if (env1->halted) {
         /* An interrupt wakes the CPU even if the I and F CPSR bits are
-           set.  */
-        if (env1->interrupt_request
-            & (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD)) {
+           set.  We use EXITTB to silently wake CPU without causing an
+           actual interrupt.  */
+        if (env1->interrupt_request &
+            (CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) {
             env1->halted = 0;
         } else {
             return EXCP_HALTED;
@@ -432,6 +433,15 @@ int cpu_exec(CPUState *env1)
                         env->exception_index = EXCP_DEBUG;
                         cpu_loop_exit();
                     }
+#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
+    defined(TARGET_PPC) || defined(TARGET_ALPHA)
+                    if (interrupt_request & CPU_INTERRUPT_HALT) {
+                        env->interrupt_request &= ~CPU_INTERRUPT_HALT;
+                        env->halted = 1;
+                        env->exception_index = EXCP_HLT;
+                        cpu_loop_exit();
+                    }
+#endif
 #if defined(TARGET_I386)
                     if ((interrupt_request & CPU_INTERRUPT_SMI) &&
                         !(env->hflags & HF_SMM_MASK)) {
@@ -514,12 +524,7 @@ int cpu_exec(CPUState *env1)
                    } else if (interrupt_request & CPU_INTERRUPT_TIMER) {
                        //do_interrupt(0, 0, 0, 0, 0);
                        env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
-                   } else if (interrupt_request & CPU_INTERRUPT_HALT) {
-                       env->interrupt_request &= ~CPU_INTERRUPT_HALT;
-                       env->halted = 1;
-                       env->exception_index = EXCP_HLT;
-                       cpu_loop_exit();
-                    }
+                   }
 #elif defined(TARGET_ARM)
                     if (interrupt_request & CPU_INTERRUPT_FIQ
                         && !(env->uncached_cpsr & CPSR_F)) {
index 2f5dc96062aeebde6624519200a1b727e7cff7d6..43d40c7fd9b8d8800e6c62eacc41e4820e0de17b 100644 (file)
@@ -247,7 +247,8 @@ static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
             goto message;
 
         case 3:
-            cpu_reset(s->env);
+            s->env->uncached_cpsr =
+                    ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
             s->env->cp15.c1_sys = 0;
             s->env->cp15.c1_coproc = 0;
             s->env->cp15.c2 = 0;
index 3d3dc3fd26888d99296bee7d09d23ba282d57d84..364f4eadba9d5e98c0f1dc6582cdef98d70d0b62 100644 (file)
@@ -1584,7 +1584,7 @@ static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
 
 /* Disassemble system coprocessor (cp15) instruction.  Return nonzero if
    instruction is not defined.  */
-static int disas_cp15_insn(DisasContext *s, uint32_t insn)
+static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
 {
     uint32_t rd;
 
@@ -1610,8 +1610,13 @@ static int disas_cp15_insn(DisasContext *s, uint32_t insn)
     } else {
         gen_movl_T0_reg(s, rd);
         gen_op_movl_cp15_T0(insn);
+        /* Normally we would always end the TB here, but Linux
+         * arch/arm/mach-pxa/sleep.S expects two instructions following
+         * an MMU enable to execute from cache.  Imitate this behaviour.  */
+        if (!arm_feature(env, ARM_FEATURE_XSCALE) ||
+                (insn & 0x0fff0fff) != 0x0e010f10)
+            gen_lookup_tb(s);
     }
-    gen_lookup_tb(s);
     return 0;
 }
 
@@ -2927,7 +2932,7 @@ static void disas_arm_insn(CPUState * env, DisasContext *s)
                     goto illegal_op;
                 break;
             case 15:
-                if (disas_cp15_insn (s, insn))
+                if (disas_cp15_insn (env, s, insn))
                     goto illegal_op;
                 break;
             default: