diff options
Diffstat (limited to 'firmware/target/mips/ingenic_jz47xx/system-jz4740.c')
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/system-jz4740.c | 122 |
1 files changed, 72 insertions, 50 deletions
diff --git a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c index 8f1c3f5c1a..61be6c60de 100644 --- a/firmware/target/mips/ingenic_jz47xx/system-jz4740.c +++ b/firmware/target/mips/ingenic_jz47xx/system-jz4740.c | |||
@@ -555,21 +555,7 @@ void dma_cache_wback_inv(unsigned long addr, unsigned long size) | |||
555 | } | 555 | } |
556 | } | 556 | } |
557 | 557 | ||
558 | extern int main(void); | 558 | #define BARRIER \ |
559 | extern void except_common_entry(void); | ||
560 | |||
561 | #define mtc0_tlbw_hazard() \ | ||
562 | __asm__ __volatile__( \ | ||
563 | " .set noreorder \n" \ | ||
564 | " nop \n" \ | ||
565 | " nop \n" \ | ||
566 | " nop \n" \ | ||
567 | " nop \n" \ | ||
568 | " nop \n" \ | ||
569 | " nop \n" \ | ||
570 | " .set reorder \n"); | ||
571 | |||
572 | #define tlbw_use_hazard() \ | ||
573 | __asm__ __volatile__( \ | 559 | __asm__ __volatile__( \ |
574 | " .set noreorder \n" \ | 560 | " .set noreorder \n" \ |
575 | " nop \n" \ | 561 | " nop \n" \ |
@@ -580,10 +566,13 @@ extern void except_common_entry(void); | |||
580 | " nop \n" \ | 566 | " nop \n" \ |
581 | " .set reorder \n"); | 567 | " .set reorder \n"); |
582 | 568 | ||
583 | 569 | #define DEFAULT_PAGE_SHIFT PL_4K | |
584 | #define PAGE_SHIFT PL_4K | 570 | #define DEFAULT_PAGE_MASK PM_4K |
585 | #define PM_DEFAULT_MASK PM_4K | 571 | #define UNIQUE_ENTRYHI(idx, ps) (A_K0BASE + ((idx) << (ps + 1))) |
586 | #define UNIQUE_ENTRYHI(idx) (A_K0BASE + ((idx) << (PAGE_SHIFT + 1))) | 572 | #define ASID_MASK M_EntryHiASID |
573 | #define VPN2_SHIFT S_EntryHiVPN2 | ||
574 | #define PFN_SHIFT S_EntryLoPFN | ||
575 | #define PFN_MASK 0xffffff | ||
587 | static void local_flush_tlb_all(void) | 576 | static void local_flush_tlb_all(void) |
588 | { | 577 | { |
589 | unsigned long old_ctx; | 578 | unsigned long old_ctx; |
@@ -594,59 +583,92 @@ static void local_flush_tlb_all(void) | |||
594 | old_ctx = read_c0_entryhi(); | 583 | old_ctx = read_c0_entryhi(); |
595 | write_c0_entrylo0(0); | 584 | write_c0_entrylo0(0); |
596 | write_c0_entrylo1(0); | 585 | write_c0_entrylo1(0); |
586 | BARRIER; | ||
597 | 587 | ||
598 | /* Blast 'em all away. */ | 588 | /* Blast 'em all away. */ |
599 | for(entry = read_c0_wired(); entry < 32; entry++) | 589 | for(entry = 0; entry < 32; entry++) |
600 | { | 590 | { |
601 | /* Make sure all entries differ. */ | 591 | /* Make sure all entries differ. */ |
602 | write_c0_entryhi(UNIQUE_ENTRYHI(entry)); | 592 | write_c0_entryhi(UNIQUE_ENTRYHI(entry, DEFAULT_PAGE_SHIFT)); |
603 | write_c0_index(entry); | 593 | write_c0_index(entry); |
604 | mtc0_tlbw_hazard(); | 594 | BARRIER; |
605 | tlb_write_indexed(); | 595 | tlb_write_indexed(); |
606 | } | 596 | } |
607 | tlbw_use_hazard(); | 597 | BARRIER; |
608 | write_c0_entryhi(old_ctx); | 598 | write_c0_entryhi(old_ctx); |
609 | 599 | ||
610 | restore_irq(old_irq); | 600 | restore_irq(old_irq); |
611 | } | 601 | } |
612 | 602 | ||
603 | static void add_wired_entry(unsigned long entrylo0, unsigned long entrylo1, | ||
604 | unsigned long entryhi, unsigned long pagemask) | ||
605 | { | ||
606 | unsigned long wired; | ||
607 | unsigned long old_pagemask; | ||
608 | unsigned long old_ctx; | ||
609 | unsigned int old_irq = disable_irq_save(); | ||
610 | |||
611 | old_ctx = read_c0_entryhi() & ASID_MASK; | ||
612 | old_pagemask = read_c0_pagemask(); | ||
613 | wired = read_c0_wired(); | ||
614 | write_c0_wired(wired + 1); | ||
615 | write_c0_index(wired); | ||
616 | BARRIER; | ||
617 | write_c0_pagemask(pagemask); | ||
618 | write_c0_entryhi(entryhi); | ||
619 | write_c0_entrylo0(entrylo0); | ||
620 | write_c0_entrylo1(entrylo1); | ||
621 | BARRIER; | ||
622 | tlb_write_indexed(); | ||
623 | BARRIER; | ||
624 | |||
625 | write_c0_entryhi(old_ctx); | ||
626 | BARRIER; | ||
627 | write_c0_pagemask(old_pagemask); | ||
628 | local_flush_tlb_all(); | ||
629 | restore_irq(old_irq); | ||
630 | } | ||
631 | |||
632 | static void map_address(unsigned long virtual, unsigned long physical, unsigned long length) | ||
633 | { | ||
634 | unsigned long entry0 = (physical & PFN_MASK) << PFN_SHIFT; | ||
635 | unsigned long entry1 = ((physical+length) & PFN_MASK) << PFN_SHIFT; | ||
636 | unsigned long entryhi = virtual & ~VPN2_SHIFT; | ||
637 | |||
638 | entry0 |= (M_EntryLoG | M_EntryLoV | (K_CacheAttrC << S_EntryLoC) ); | ||
639 | entry1 |= (M_EntryLoG | M_EntryLoV | (K_CacheAttrC << S_EntryLoC) ); | ||
640 | |||
641 | add_wired_entry(entry0, entry1, entryhi, DEFAULT_PAGE_MASK); | ||
642 | } | ||
643 | |||
613 | 644 | ||
614 | static void tlb_init(void) | 645 | static void tlb_init(void) |
615 | { | 646 | { |
616 | write_c0_pagemask(PM_DEFAULT_MASK); | 647 | write_c0_pagemask(DEFAULT_PAGE_MASK); |
617 | write_c0_wired(0); | 648 | write_c0_wired(0); |
618 | write_c0_framemask(0); | 649 | write_c0_framemask(0); |
619 | 650 | ||
620 | local_flush_tlb_all(); | 651 | local_flush_tlb_all(); |
652 | /* | ||
653 | map_address(0x80000000, 0x80000000, 0x4000); | ||
654 | map_address(0x80004000, 0x80004000, MEM * 0x100000); | ||
655 | */ | ||
621 | } | 656 | } |
622 | 657 | ||
623 | static void tlb_refill_handler(void) | 658 | void tlb_refill_handler(void) |
624 | { | 659 | { |
625 | #if 1 | 660 | panicf("TLB refill handler! [0x%x] [0x%lx]", read_c0_badvaddr(), read_c0_epc()); |
626 | panicf("TLB refill handler! [0x%x] [0x%x]", read_c0_badvaddr(), read_c0_epc()); | ||
627 | #else | ||
628 | __asm__ __volatile__( | ||
629 | "mfc0 k0, C0_BADVADDR\n" | ||
630 | "lui k1, pgdc\n" | ||
631 | "lw k1, pgdc>>16(k0)\n" | ||
632 | "srl k0, k0, 22\n" | ||
633 | "sll k0, k0, 2\n" | ||
634 | "addu k1, k1, k0\n" | ||
635 | "mfc0 k0, C0_CONTEXT\n" | ||
636 | "lw k1, 0(k1)\n" | ||
637 | "andi k0, k0, 0xFFC\n" | ||
638 | "addu k1, k1, k0\n" | ||
639 | "lw k0, 0(k1)\n" | ||
640 | "nop\n" | ||
641 | "mtc0 k0, C0_ENTRYLO0\n" | ||
642 | "mfc0 k1, C0_EPC\n" | ||
643 | "tlbwr\n" | ||
644 | "jr k1\n" | ||
645 | "rfe\n" | ||
646 | ); | ||
647 | #endif | ||
648 | } | 661 | } |
649 | 662 | ||
663 | static void tlb_call_refill(void) | ||
664 | { | ||
665 | asm("la $8, tlb_refill_handler \n" | ||
666 | "jr $8 \n"); | ||
667 | } | ||
668 | |||
669 | extern int main(void); | ||
670 | extern void except_common_entry(void); | ||
671 | |||
650 | void system_main(void) | 672 | void system_main(void) |
651 | { | 673 | { |
652 | int i; | 674 | int i; |
@@ -657,7 +679,7 @@ void system_main(void) | |||
657 | * 0x180 - Exception/Interrupt handler | 679 | * 0x180 - Exception/Interrupt handler |
658 | * 0x200 - Special Exception Interrupt handler (when IV is set in CP0_CAUSE) | 680 | * 0x200 - Special Exception Interrupt handler (when IV is set in CP0_CAUSE) |
659 | */ | 681 | */ |
660 | memcpy((void *)A_K0BASE, (void *)&tlb_refill_handler, 0x20); | 682 | memcpy((void *)A_K0BASE, (void *)&tlb_call_refill, 0x20); |
661 | memcpy((void *)(A_K0BASE + 0x100), (void *)&except_common_entry, 0x20); | 683 | memcpy((void *)(A_K0BASE + 0x100), (void *)&except_common_entry, 0x20); |
662 | memcpy((void *)(A_K0BASE + 0x180), (void *)&except_common_entry, 0x20); | 684 | memcpy((void *)(A_K0BASE + 0x180), (void *)&except_common_entry, 0x20); |
663 | memcpy((void *)(A_K0BASE + 0x200), (void *)&except_common_entry, 0x20); | 685 | memcpy((void *)(A_K0BASE + 0x200), (void *)&except_common_entry, 0x20); |
@@ -671,7 +693,7 @@ void system_main(void) | |||
671 | for(i=0; i<IRQ_MAX; i++) | 693 | for(i=0; i<IRQ_MAX; i++) |
672 | dis_irq(i); | 694 | dis_irq(i); |
673 | 695 | ||
674 | tlb_init(); | 696 | //tlb_init(); |
675 | 697 | ||
676 | sti(); | 698 | sti(); |
677 | 699 | ||