@@ -217,9 +217,10 @@ static void hal_flash_init(void)
217217 wolfBoot_printf ("IFC CSPR0: 0x%x%s\n" , cspr ,
218218 (cspr & IFC_CSPR_WP ) ? " (WP set)" : "" );
219219#endif
220- if (cspr & IFC_CSPR_WP ) {
221- set32 (IFC_CSPR (0 ), cspr & ~IFC_CSPR_WP );
222- }
220+ /* WP clearing is done in hal_flash_clear_wp() from RAMFUNCTION code.
221+ * T2080RM requires V=0 before modifying IFC_CSPR, which is not safe
222+ * during XIP. The RAMFUNCTION code runs from DDR with flash TLB
223+ * guarded, so it can safely toggle V=0 -> modify -> V=1. */
223224
224225 /* Note: hal_flash_getid() is disabled because AMD Autoselect mode
225226 * affects the entire flash bank. Since wolfBoot runs XIP from the same
@@ -676,52 +677,132 @@ static void RAMFUNCTION ram_udelay(uint32_t delay_us)
676677 } while ((tbl_now - tbl_start ) < ticks );
677678}
678679
679- /* Switch flash TLB to cache-inhibited for direct flash chip access.
680- * AMD flash commands require writes to reach the chip immediately and
681- * status reads to come directly from the chip. With MAS2_M (cacheable),
682- * writes are cached and never reach the flash, reads return stale data.
683- * Uses direct SPR manipulation to avoid calling .text functions. */
680+ /* Switch flash TLB to cache-inhibited + guarded for direct flash chip access.
681+ * AMD flash commands require writes to reach the chip immediately and status
682+ * reads to come directly from the chip. With MAS2_M (cacheable), stores go
683+ * through the CPC coherency fabric; IFC does not support coherent writes and
684+ * returns a bus error (DSI). tlbre/tlbwe only modifies MAS2 and is unreliable
685+ * when the entry has IPROT=1; use set_tlb() to rewrite all MAS fields.
686+ * Must be called while flash is still in read-array mode (set_tlb lives in
687+ * flash .text, reachable via longcall while TLB is still M/cacheable). */
684688static void RAMFUNCTION hal_flash_cache_disable (void )
685689{
686- uint32_t mas2 ;
687- /* Select TLB1, entry 2 (flash) */
688- mtspr (MAS0 , BOOKE_MAS0 (1 , 2 , 0 ));
689- __asm__ __volatile__("isync; tlbre; isync" );
690- /* Change WIMGE from M to I|G */
691- mas2 = mfspr (MAS2 );
692- mas2 &= ~0x1F ; /* clear WIMGE bits */
693- mas2 |= (MAS2_I | MAS2_G );
694- mtspr (MAS2 , mas2 );
695- __asm__ __volatile__("isync; msync; tlbwe; isync" );
690+ set_tlb (1 , 2 ,
691+ FLASH_BASE_ADDR , FLASH_BASE_ADDR , FLASH_BASE_PHYS_HIGH ,
692+ MAS3_SX | MAS3_SW | MAS3_SR , MAS2_I | MAS2_G , 0 ,
693+ FLASH_TLB_PAGESZ , 1 );
696694}
697695
698696/* Restore flash TLB to cacheable mode after flash operation.
699- * Flash is back in read-array mode, safe to cache again. */
697+ * Flash must be back in read-array mode before calling (AMD_CMD_RESET sent).
698+ * Invalidate caches afterward so stale pre-erase data is not served. */
700699static void RAMFUNCTION hal_flash_cache_enable (void )
701700{
702- uint32_t mas2 ;
703- /* Select TLB1, entry 2 (flash) */
704- mtspr (MAS0 , BOOKE_MAS0 (1 , 2 , 0 ));
705- __asm__ __volatile__("isync; tlbre; isync" );
706- /* Change WIMGE from I|G to M (cacheable) */
707- mas2 = mfspr (MAS2 );
708- mas2 &= ~0x1F ;
709- mas2 |= MAS2_M ;
710- mtspr (MAS2 , mas2 );
711- __asm__ __volatile__("isync; msync; tlbwe; isync" );
712- /* Invalidate D-cache and I-cache — stale entries from before
713- * the flash operation must be discarded */
701+ set_tlb (1 , 2 ,
702+ FLASH_BASE_ADDR , FLASH_BASE_ADDR , FLASH_BASE_PHYS_HIGH ,
703+ MAS3_SX | MAS3_SW | MAS3_SR , MAS2_M , 0 ,
704+ FLASH_TLB_PAGESZ , 1 );
714705 invalidate_dcache ();
715706 invalidate_icache ();
716707}
717708
709+ /* Clear IFC write-protect. T2080RM says IFC_CSPR should only be written
710+ * when V=0. Must be called from RAMFUNCTION (DDR) with flash TLB set to
711+ * guarded (MAS2_G) so no speculative access occurs while V is briefly 0. */
712+ static void RAMFUNCTION hal_flash_clear_wp (void )
713+ {
714+ uint32_t cspr = get32 (IFC_CSPR (0 ));
715+ if (cspr & IFC_CSPR_WP ) {
716+ /* Clear V first, then modify WP, then re-enable V */
717+ set32 (IFC_CSPR (0 ), cspr & ~(IFC_CSPR_WP | IFC_CSPR_V ));
718+ __asm__ __volatile__("sync; isync" );
719+ set32 (IFC_CSPR (0 ), (cspr & ~IFC_CSPR_WP ) | IFC_CSPR_V );
720+ __asm__ __volatile__("sync; isync" );
721+ /* Verify WP cleared */
722+ cspr = get32 (IFC_CSPR (0 ));
723+ wolfBoot_printf ("WP clear: CSPR0=0x%x%s\n" , cspr ,
724+ (cspr & IFC_CSPR_WP ) ? " (FAILED)" : " (OK)" );
725+ }
726+ }
727+
718728static void RAMFUNCTION hal_flash_unlock_sector (uint32_t sector )
719729{
720730 /* AMD unlock sequence */
721731 FLASH_IO8_WRITE (sector , FLASH_UNLOCK_ADDR1 , AMD_CMD_UNLOCK_START );
722732 FLASH_IO8_WRITE (sector , FLASH_UNLOCK_ADDR2 , AMD_CMD_UNLOCK_ACK );
723733}
724734
735+ /* Check and clear PPB (Persistent Protection Bits) for a sector.
736+ * S29GL01GS has per-sector non-volatile protection bits. If set, erase/program
737+ * fails with DQ5 error. PPB erase is chip-wide (clears ALL sectors).
738+ * Returns: 0 if unprotected or successfully cleared, -1 on failure. */
739+ static int RAMFUNCTION hal_flash_ppb_unlock (uint32_t sector )
740+ {
741+ uint16_t ppb_status ;
742+ uint16_t read1 , read2 ;
743+ uint32_t timeout ;
744+
745+ /* Enter PPB ASO (Address Space Overlay) */
746+ FLASH_IO8_WRITE (0 , FLASH_UNLOCK_ADDR1 , AMD_CMD_UNLOCK_START );
747+ FLASH_IO8_WRITE (0 , FLASH_UNLOCK_ADDR2 , AMD_CMD_UNLOCK_ACK );
748+ FLASH_IO8_WRITE (0 , FLASH_UNLOCK_ADDR1 , AMD_CMD_SET_PPB_ENTRY );
749+
750+ /* Read PPB status for target sector: DQ0=0 means protected */
751+ ppb_status = FLASH_IO8_READ (sector , 0 );
752+
753+ if ((ppb_status & 0x0101 ) == 0x0101 ) {
754+ /* Both chips report unprotected — exit PPB mode and return */
755+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_SET_PPB_EXIT_BC1 );
756+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_SET_PPB_EXIT_BC2 );
757+ return 0 ;
758+ }
759+
760+ /* Exit PPB ASO before calling printf (flash must be in read-array
761+ * mode for I-cache misses to fetch valid instructions) */
762+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_SET_PPB_EXIT_BC1 );
763+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_SET_PPB_EXIT_BC2 );
764+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_RESET );
765+ ram_udelay (50 );
766+
767+ wolfBoot_printf ("PPB: sector %d protected (0x%x), erasing all PPBs\n" ,
768+ sector , ppb_status );
769+
770+ /* Re-enter PPB ASO for erase */
771+ FLASH_IO8_WRITE (0 , FLASH_UNLOCK_ADDR1 , AMD_CMD_UNLOCK_START );
772+ FLASH_IO8_WRITE (0 , FLASH_UNLOCK_ADDR2 , AMD_CMD_UNLOCK_ACK );
773+ FLASH_IO8_WRITE (0 , FLASH_UNLOCK_ADDR1 , AMD_CMD_SET_PPB_ENTRY );
774+
775+ /* PPB Erase All (clears all sectors' PPBs) */
776+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_PPB_UNLOCK_BC1 ); /* 0x80 */
777+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_PPB_UNLOCK_BC2 ); /* 0x30 */
778+
779+ /* Wait for PPB erase completion — poll for toggle stop */
780+ timeout = 0 ;
781+ do {
782+ read1 = FLASH_IO8_READ (0 , 0 );
783+ read2 = FLASH_IO8_READ (0 , 0 );
784+ if (read1 == read2 )
785+ break ;
786+ ram_udelay (10 );
787+ } while (timeout ++ < 100000 ); /* 1 second */
788+
789+ /* Exit PPB ASO */
790+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_SET_PPB_EXIT_BC1 );
791+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_SET_PPB_EXIT_BC2 );
792+
793+ /* Reset to read-array mode */
794+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_RESET );
795+ ram_udelay (50 );
796+
797+ if (timeout >= 100000 ) {
798+ wolfBoot_printf ("PPB: erase timeout\n" );
799+ return -1 ;
800+ }
801+
802+ wolfBoot_printf ("PPB: erase complete\n" );
803+ return 0 ;
804+ }
805+
725806/* wait for toggle to stop and status mask to be met within microsecond timeout.
726807 * RAMFUNCTION: executes from DDR while flash is in program/erase command mode. */
727808static int RAMFUNCTION hal_flash_status_wait (uint32_t sector , uint16_t mask ,
@@ -773,6 +854,12 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
773854
774855 /* Disable flash caching — AMD commands must reach the chip directly */
775856 hal_flash_cache_disable ();
857+ hal_flash_clear_wp ();
858+
859+ /* Reset flash to read-array mode in case previous operation left it
860+ * in command mode (e.g. after a timeout or incomplete operation) */
861+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_RESET );
862+ ram_udelay (50 );
776863
777864 pos = 0 ;
778865 while (len > 0 ) {
@@ -792,18 +879,15 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
792879
793880 hal_flash_unlock_sector (sector );
794881 FLASH_IO8_WRITE (sector , offset , AMD_CMD_WRITE_TO_BUFFER );
795- #if FLASH_CFI_WIDTH == 16
796- FLASH_IO16_WRITE (sector , offset , (nwords - 1 ));
797- #else
882+ /* Word count (N-1) must be replicated to both chips */
798883 FLASH_IO8_WRITE (sector , offset , (nwords - 1 ));
799- #endif
800884
801885 for (i = 0 ; i < nwords ; i ++ ) {
802886 const uint8_t * ptr = & data [pos ];
803887 #if FLASH_CFI_WIDTH == 16
804- FLASH_IO16_WRITE (sector , i , * ((const uint16_t * )ptr ));
888+ FLASH_IO16_WRITE (sector , offset + i , * ((const uint16_t * )ptr ));
805889 #else
806- FLASH_IO8_WRITE (sector , i , * ptr );
890+ FLASH_IO8_WRITE (sector , offset + i , * ptr );
807891 #endif
808892 pos += (FLASH_CFI_WIDTH /8 );
809893 }
@@ -813,6 +897,9 @@ int RAMFUNCTION hal_flash_write(uint32_t address, const uint8_t *data, int len)
813897 /* poll for program completion - max 200ms */
814898 ret = hal_flash_status_wait (sector , 0x44 , 200 * 1000 );
815899 if (ret != 0 ) {
900+ /* Reset flash to read-array mode BEFORE calling printf */
901+ FLASH_IO8_WRITE (sector , 0 , AMD_CMD_RESET );
902+ ram_udelay (50 );
816903 wolfBoot_printf ("Flash Write: Timeout at sector %d\n" , sector );
817904 break ;
818905 }
@@ -837,6 +924,12 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
837924
838925 /* Disable flash caching — AMD commands must reach the chip directly */
839926 hal_flash_cache_disable ();
927+ hal_flash_clear_wp ();
928+
929+ /* Reset flash to read-array mode in case previous operation left it
930+ * in command mode (e.g. after a timeout or incomplete operation) */
931+ FLASH_IO8_WRITE (0 , 0 , AMD_CMD_RESET );
932+ ram_udelay (50 );
840933
841934 while (len > 0 ) {
842935 /* determine sector address */
@@ -847,20 +940,41 @@ int RAMFUNCTION hal_flash_erase(uint32_t address, int len)
847940 sector , address , len );
848941 #endif
849942
943+ /* Check and clear PPB protection if set */
944+ if (hal_flash_ppb_unlock (sector ) != 0 ) {
945+ wolfBoot_printf ("Flash Erase: PPB unlock failed sector %d\n" , sector );
946+ ret = -1 ;
947+ break ;
948+ }
949+
950+ wolfBoot_printf ("Erasing sector %d...\n" , sector );
951+
850952 hal_flash_unlock_sector (sector );
851953 FLASH_IO8_WRITE (sector , FLASH_UNLOCK_ADDR1 , AMD_CMD_ERASE_START );
852954 hal_flash_unlock_sector (sector );
853955 FLASH_IO8_WRITE (sector , 0 , AMD_CMD_ERASE_SECTOR );
854956 /* block erase timeout = 50us - for additional sectors */
855957 /* Typical is 200ms (max 1100ms) */
856958
857- /* poll for erase completion - max 1.1 sec */
959+ /* poll for erase completion - max 1.1 sec
960+ * NOTE: Do NOT call wolfBoot_printf while flash is in erase mode.
961+ * With cache-inhibited TLB, I-cache misses fetch from flash which
962+ * returns status data instead of instructions. */
858963 ret = hal_flash_status_wait (sector , 0x4C , 1100 * 1000 );
859964 if (ret != 0 ) {
965+ /* Reset flash to read-array mode BEFORE calling printf */
966+ FLASH_IO8_WRITE (sector , 0 , AMD_CMD_RESET );
967+ ram_udelay (50 );
860968 wolfBoot_printf ("Flash Erase: Timeout at sector %d\n" , sector );
861969 break ;
862970 }
863971
972+ /* Erase succeeded — flash is back in read-array mode.
973+ * Reset to be safe before any printf (I-cache may miss) */
974+ FLASH_IO8_WRITE (sector , 0 , AMD_CMD_RESET );
975+ ram_udelay (10 );
976+ wolfBoot_printf ("Erase sector %d: OK\n" , sector );
977+
864978 address += FLASH_SECTOR_SIZE ;
865979 len -= FLASH_SECTOR_SIZE ;
866980 }
0 commit comments