2 * BCM47XX Sonics SiliconBackplane SDRAM/MEMC core initialization
4 * Copyright 2005, Broadcom Corporation
7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY
8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM
9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE.
12 * $Id: sbsdram.S,v 1.7 2005/03/07 08:35:32 kanki Exp $
25 /* #define DEBUG_SBSDRAM 1 */
28 * Write to prog space so we can see it in
39 #define TRACE(num, reg) sw reg,(num << 4)(k0)
41 #define TRACE(num, reg)
45 * Register usage within this file:
47 * top ncdlsearch test_mem Xdr_do_init sb_reset_core
49 * v1: corerev - - corerev -
50 * a0: coreptr coreptr - coreptr coreptr
51 * a1: x x x sdr/ddr flag
56 * t2: - wr/strm off wr/strm
57 * t3: - rd/strd rd/strd
63 * s1: wrsum/clkdsum - -
64 * s2: rdsum/pass_countmax - -
65 * s3: gsum/strmmax - -
66 * s4: wrlim/stdmmax - -
67 * s5: rdlim/clkdmax - -
68 * s6: glim/clkdlim - -
72 * k0: trace trace trace - -
73 * k1: trace trace trace - -
84 /* Save return address */
89 /* Scan for an SDRAM controller (a0) */
90 li a0,KSEG1ADDR(SB_ENUM_BASE)
91 1: lw v1,(SBCONFIGOFF + SBIDHIGH)(a0)
92 and a1,v1,SBIDH_CC_MASK
93 srl a1,a1,SBIDH_CC_SHIFT
94 beq a1,SB_MEMC,foundctrl
96 beq a1,SB_SOCRAM,foundctrl
98 beq a1,SB_SDRAM,foundctrl
101 bne a1,(SBIDH_CC_MASK >> SBIDH_CC_SHIFT),1b
104 /* No SDRAM controller */
109 /* If we are already in RAM, just go and size it */
112 1: li t0,PHYSADDR_MASK
115 blt t0,t1,memprio_szmem
118 /* For socram we don't need any nvram parms, just do a core reset */
119 bne a1,SB_SOCRAM,read_nvram
123 /* and size memory */
128 /* Find NVRAM (a2) */
129 li t0,KSEG1ADDR(SB_ENUM_BASE) # Is there a chipcommon core?
130 lw t1,(SBCONFIGOFF + SBIDHIGH)(t0)
131 and t1,t1,SBIDH_CC_MASK
132 srl t1,t1,SBIDH_CC_SHIFT
136 /* It is a chipcommon core: */
137 /* 1: Isolate corerev in v1 */
138 and v1,v1,SBIDH_RC_MASK
140 /* 1.5: 5365a0 lies about its revision, it is really 1 */
143 lw t1,0(t0) # Check chipid
145 bne t1,BCM5365_DEVICE_ID,1f
149 /* 2: use the 32MB window */
150 1: li t2,KSEG1ADDR(SB_FLASH2 - NVRAM_SPACE)
156 /* else use the 4MB window */
157 li t2,KSEG1ADDR(SB_FLASH1 - NVRAM_SPACE)
174 /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
175 li a2,KSEG1ADDR(SB_FLASH1 + 0x1000)
180 li a2,KSEG1ADDR(SB_FLASH1 + 0x400)
189 /* Get SDRAM parameters (t0, t1, t2) from NVRAM (a2) */
190 lw t0,8(a2) # SDRAM init
193 andi t1,t2,0xffff # SDRAM config
194 srl t2,16 # SDRAM refresh
195 lw t3,16(a2) # SDRAM ncdl
198 /* Initialize SDRAM controller: sdram core */
199 beq a1,SB_SDRAM,sdram_init
201 /* else it is a memc core */
204 bnez a2,1f # Already have the parms in
207 /* No nvram parms: assume DDRM16MX16X2 */
211 li t3,MEMC_DDR1_NCDL # If rev1 (4712):
218 andi a3,t0,MEMC_CONFIG_DDR # Is it ddr or sdr?
219 beqz a3,memc_sdr_init
222 /* Initialize DDR SDRAM */
224 beqz t3,ddr_find_ncdl # Do we have ncdl values? (0s)
228 bne t3,t4,break_ddr_ncdl
234 #define pass_count s0
247 /* Initialize counter & accumulators */
253 /* Initialize with default values */
260 lw dll,MEMC_NCDLCTL(a0)
264 beqz dll,memprio_szmem /* If zero, leave the default values */
267 move wrlim,dll /* dll value is lim for wr, rd and g */
274 addi step,dll,15 /* step = (dll + 16 - 1) / 16 */
278 sub wr,zero,dll /* Negate dll as initial value */
282 /* Inner loop: call ddr_do_init to re-initialize and the test mem */
303 TRACE(0xa, pass_count)
346 /* All done, calculate average values and program them */
348 TRACE(0x13, pass_count)
355 div zero,wrsum,pass_count
358 div zero,rdsum,pass_count
361 div zero,gsum,pass_count
367 /* No passing values, panic! (use defaults) */
369 li t3,MEMC_DDR1_NCDL # If rev1:
377 andi t4,t3,0xff # t4: g
378 srl t2,t3,16 # t2: wr
394 beqz t3,sdr_find_ncdl # Do we have ncdl values?
398 bne t3,t4,break_sdr_ncdl
404 #define pass_count s0
406 #define pass_countmax s2
418 #define CLKDLIM_IC 256
420 /* Initialize counter & saved values */
421 move pass_countmax,zero
426 and strm,t0,0x2000 /* Test for internal clock (Using strm as a temp) */
430 li clkdlim,CLKDLIM_IC
432 move strm,zero /* strm loop */
440 /* Inner loop: call sdr_do_init to re-initialize and the test mem */
458 add clkdsum,clkdsum,clkd
459 TRACE(0x1e, pass_count)
465 bnez pass_count,clkdout # End of passing range, leave clkd loop
470 blt clkd,clkdlim,clkdloop
474 /* If no passing values, skip to next strm */
475 beqz pass_count,nextstrm
478 /* If this is a new max, Save the values */
479 ble pass_count,pass_countmax,nextstrd
482 move pass_countmax,pass_count
483 div zero,clkdsum,pass_count
487 TRACE(0x20, pass_count)
494 blt strd,STRDLIM,strdloop
499 blt strm,STRMLIM,strmloop
502 /* All done, program the new ncdl values */
504 TRACE(0x24, pass_count)
509 beqz pass_countmax,1f
518 /* No passing values, panic! (use defaults) */
520 li t3,MEMC_SDR1_NCDL # If rev1:
528 andi t4,t3,0xff # t4: cd
529 srl t2,t3,16 # t2: sm
530 andi t2,t2,3 # sm is 2 bits only
532 andi t3,t3,0xf # sd is 4 bits
542 bnez a2,1f # Already have the parms in t0, t1, t2
545 /* Use default SDRAM parameters */
550 /* Initialize SDRAM */
555 sw t1, 4(a0) # SDRAM config
561 sw a1, 0(a0) # 1st refresh of power up sequence
562 sw a1, 0(a0) # 2nd refresh of power up sequence
563 sw a1, 0(a0) # 3rd refresh of power up sequence
564 sw a1, 0(a0) # 4th refresh of power up sequence
565 sw a1, 0(a0) # 5th refresh of power up sequence
566 sw a1, 0(a0) # 6th refresh of power up sequence
567 sw a1, 0(a0) # 7th refresh of power up sequence
568 sw a1, 0(a0) # 8th refresh of power up sequence
569 sw t0, 0(a0) # SDRAM init
570 sw t2, 8(a0) # SDRAM refresh
573 /* Change the memory priority inversion counter value*/
574 /* Determine memory size and return */
578 lw t0, MEMC_PRIORINV(a0)
582 sw t0, MEMC_PRIORINV(a0)
584 lw t0,(SBCONFIGOFF + SBIDHIGH)(a0)
585 and t0,t0,SBIDH_CC_MASK
586 srl t0,t0,SBIDH_CC_SHIFT
587 bne t0,SB_SOCRAM,szmem_alias
590 /* The socram core tells us how much memory there is */
591 lw t0,SOCRAM_MEMSIZE(a0)
592 addi t0,SOCRAM_MEMSIZE_BASESHIFT
611 bne v0,(128 << 20),1b
613 /* Didn't find an alias, must be 128MB */
623 * Uses arg in t2(wr/sd), t3(rd/sm) and t4(g/clkd)
624 * Returns success (1) or failure (0) in v0
625 * Uses a1, a2, a3 & t5
628 /* Use t4 to generate a semi-random address in the second KB */
634 /* First set: 0 & its negation */
648 /* Second set: 0xaaaaaaaa & its negation */
662 /* Third set: 0x12345678 & its negation */
676 /* Fourth set: the ncdl & its negation */
693 /* Fifth set: the CPU count register & its negation */
715 /* Do an init of the memc core for ddr
716 * a0: memc core pointer
717 * t0: memc config value
718 * t1: memc mode value
719 * t2: memc wr ncdl value
720 * t3: memc rd ncdl value
721 * t4: memc g ncdl value
723 * Uses a1, t7, t8, t9 (here and by calling sb_core_reset)
727 /* Save return address */
733 li a1,MEMC_CONFIG_INIT
735 sw a1,MEMC_CONFIG(a0)
737 li a1,MEMC_DRAMTIM25_INIT # Assume CAS latency of 2.5
738 andi t8,t1,0xf0 # Find out the CAS latency
741 li a1,MEMC_DRAMTIM2_INIT # CAS latency is 2
743 sw a1,MEMC_DRAMTIM(a0)
746 sll a1,t8,8 # Replicate rd ncdl 4 times
750 li a1,MEMC_RDNCDLCOR_INIT
752 sw a1,MEMC_RDNCDLCOR(a0)
754 li a1,MEMC_1_WRNCDLCOR_INIT # If rev1:
758 li a1,MEMC_WRNCDLCOR_INIT
762 sw a1,MEMC_WRNCDLCOR(a0)
764 li a1,MEMC_DQSGATENCDL_INIT
767 sw a1,MEMC_DQSGATENCDL(a0)
769 li a1,MEMC_1_MISCDLYCTL_INIT # If rev1:
773 li a1,MEMC_MISCDLYCTL_INIT
775 sw a1,MEMC_MISCDLYCTL(a0)
777 li a1,MEMC_NCDLCTL_INIT
778 sw a1,MEMC_NCDLCTL(a0)
780 li a1,MEMC_CONTROL_INIT0
781 sw a1,MEMC_CONTROL(a0)
783 li a1,MEMC_CONTROL_INIT1
784 sw a1,MEMC_CONTROL(a0)
786 li a1,MEMC_MODEBUF_INIT0
787 sw a1,MEMC_MODEBUF(a0)
789 li a1,MEMC_CONTROL_INIT2
790 sw a1,MEMC_CONTROL(a0)
792 li a1,MEMC_MODEBUF_INIT1
794 sw a1,MEMC_MODEBUF(a0)
796 li a1,MEMC_CONTROL_INIT3
797 sw a1,MEMC_CONTROL(a0)
799 li a1,MEMC_CONTROL_INIT4
800 sw a1,MEMC_CONTROL(a0)
802 li a1,MEMC_CONTROL_INIT5
803 sw a1,MEMC_CONTROL(a0)
804 lw a1,MEMC_CONTROL(a0)
805 lw a1,MEMC_CONTROL(a0)
806 lw a1,MEMC_CONTROL(a0)
808 li a1,MEMC_CONTROL_INIT5
809 sw a1,MEMC_CONTROL(a0)
810 lw a1,MEMC_CONTROL(a0)
811 lw a1,MEMC_CONTROL(a0)
812 lw a1,MEMC_CONTROL(a0)
814 li a1,MEMC_REFRESH_INIT
815 sw a1,MEMC_REFRESH(a0)
817 li a1,MEMC_MODEBUF_INIT2
819 sw a1,MEMC_MODEBUF(a0)
821 li a1,MEMC_CONTROL_INIT6
822 sw a1,MEMC_CONTROL(a0)
824 li a1,MEMC_CONTROL_INIT7
825 sw a1,MEMC_CONTROL(a0)
827 /* Wait for SDRAM controller to refresh.
831 1: lw a1,(SBCONFIGOFF + SBIDLOW)(a0)
832 lw a1,(SBCONFIGOFF + SBIDHIGH)(a0)
840 /* Do an init of the memc core for sdr
841 * a0: memc core pointer
842 * t0: memc config value
843 * t1: memc mode value
844 * t2: memc strobe mode ncdl value
845 * t3: memc strobe delay ncdl value
846 * t4: memc clock delay ncdl value
848 * Uses a1, t7, t8, t9 (here and by calling sb_core_reset)
852 /* Save return address */
858 /* Initialize SDRAM */
859 li a1,MEMC_SD_CONFIG_INIT
861 sw a1,MEMC_CONFIG(a0)
863 li a1,MEMC_SD_DRAMTIM3_INIT # Assume CAS latency of 3
864 andi t8,t1,0xf0 # Find out the CAS latency
867 li a1,MEMC_SD_DRAMTIM2_INIT # CAS latency is 2
869 sw a1,MEMC_DRAMTIM(a0)
872 ble t8,MEMC_CD_THRESHOLD,1f # if (cd <= MEMC_CD_THRESHOLD) rd = cd
875 li t8,MEMC_CD_THRESHOLD # else rd = MEMC_CD_THRESHOLD
878 sll a1,t8,8 # .. replicate it 4 times
882 li a1,MEMC_SD_RDNCDLCOR_INIT
884 sw a1,MEMC_RDNCDLCOR(a0)
886 li a1,MEMC_SD1_WRNCDLCOR_INIT # rev1
890 li a1,MEMC_SD_WRNCDLCOR_INIT # rev0, 2
893 ble t4,MEMC_CD_THRESHOLD,2f # if (cd <= MEMC_CD_THRESHOLD) wr = 0
896 andi t8,t4,0xff # else wr = cd - MEMC_CD_THRESHOLD
897 sub t8,t8,MEMC_CD_THRESHOLD
900 2: # t8 is now wr, a0 is extra bits
902 sw a1,MEMC_WRNCDLCOR(a0)
909 li a1,MEMC_SD1_MISCDLYCTL_INIT
910 beq v1,1,3f # If rev1:
913 li a1,MEMC_SD_MISCDLYCTL_INIT
916 sw a1,MEMC_MISCDLYCTL(a0)
918 li a1,MEMC_SD_CONTROL_INIT0
919 sw a1,MEMC_CONTROL(a0)
921 li a1,MEMC_SD_CONTROL_INIT1
922 sw a1,MEMC_CONTROL(a0)
924 li a1,MEMC_SD_CONTROL_INIT2
925 sw a1,MEMC_CONTROL(a0)
926 lw a1,MEMC_CONTROL(a0)
927 lw a1,MEMC_CONTROL(a0)
928 lw a1,MEMC_CONTROL(a0)
930 li a1,MEMC_SD_CONTROL_INIT2
931 sw a1,MEMC_CONTROL(a0)
932 lw a1,MEMC_CONTROL(a0)
933 lw a1,MEMC_CONTROL(a0)
934 lw a1,MEMC_CONTROL(a0)
936 li a1,MEMC_SD_CONTROL_INIT2
937 sw a1,MEMC_CONTROL(a0)
938 lw a1,MEMC_CONTROL(a0)
939 lw a1,MEMC_CONTROL(a0)
940 lw a1,MEMC_CONTROL(a0)
942 li a1,MEMC_SD_REFRESH_INIT
943 sw a1,MEMC_REFRESH(a0)
945 li a1,MEMC_SD_MODEBUF_INIT
947 sw a1,MEMC_MODEBUF(a0)
949 li a1,MEMC_SD_CONTROL_INIT3
950 sw a1,MEMC_CONTROL(a0)
952 li a1,MEMC_SD_CONTROL_INIT4
953 sw a1,MEMC_CONTROL(a0)
956 1: lw a1,(SBCONFIGOFF + SBIDLOW)(a0)
957 lw a1,(SBCONFIGOFF + SBIDHIGH)(a0)
965 /* Special sb_core_reset that makes sure the first time
966 * clock is enabled, address line 6 is in the state specified
970 * a1: 0x40 if a6 needs to be 1, 0 otherwise
978 /* Save return address */
985 /* Figure out our address */
988 h0: add t8,ra,24 # This is (h1 - h0)
990 bne t8,a1,alt_core_reset
993 /* Set reset while enabling the clock */
994 li t8,(SBTML_FGC | SBTML_CLK | SBTML_RESET)
995 h1: sw t8,(SBCONFIGOFF + SBTMSTATELOW)(a0)
999 /* Now pad to 0x40: We want (h2 - h1) == 0x40 and there
1000 * are 5 instructions inbetween them.
1005 /* Set reset while enabling the clock */
1006 li t8,(SBTML_FGC | SBTML_CLK | SBTML_RESET)
1007 h2: sw t8,(SBCONFIGOFF + SBTMSTATELOW)(a0)
1010 /* Read back and delay */
1011 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1012 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1013 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1016 li t8, (SBTML_FGC | SBTML_CLK)
1017 sw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1019 /* Read back and delay */
1020 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1021 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1022 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1024 /* Leave clock enabled */
1026 sw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1028 /* Read back and delay */
1029 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1030 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1031 lw t8, (SBCONFIGOFF + SBTMSTATELOW)(a0)
1038 and ra,ra,PHYSADDR_MASK