1#include <arminc.h> 2#include <hndsoc.h> 3#include <sbchipc.h> 4 5#ifndef __arm__ 6#error __arm__ is NOT defined 7#endif 8 9/* Routine begin/end macro */ 10#if defined(__thumb__) 11#define FUNC(x) THUMBLEAF(x) 12#else 13#define FUNC(x) LEAF(x) 14#endif /* __thumb__ */ 15 16#ifdef BCMDBG 17#define TRACE(x) \ 18 ldr r9,=(x); \ 19 ldr r10,=SI_ENUM_BASE; \ 20 str r9,[r10,#0x64] 21 22#define TRACE1(x) \ 23 mov r9,x; \ 24 ldr r10,=SI_ENUM_BASE; \ 25 str r9,[r10,#0x68] 26 27#define TRACE2(x) \ 28 mov r9,x; \ 29 ldr r10,=SI_ENUM_BASE; \ 30 str r9,[r10,#0x64] 31#else 32#define TRACE(x) 33#define TRACE1(x) 34#define TRACE2(x) 35#endif 36 37 .text 38 39FUNC(pcie_phy_init) 40 mov r6,lr 41 /* 42 * Sys Init code -- read OTP, program the H/W blocks 43 * At completion, take a jump to __hw_init_done 44 */ 45__sys_init: 46 47 ldr r0,=SI_ENUM_BASE /* r0: core regs SI base address */ 48 ldr r4,[r0,#CC_CAPABILITIES] /* r4: capabitilies */ 49 and r4,r4,#CC_CAP_OTPSIZE 50 cmp r4,#0 51 beq __hw_init_done 52 ldr r1,[r0,#CC_CLKDIV] 53 mov r2,#~CLKD_OTP 54 and r2,r2,r1 55 mov r1,#(0xe << CLKD_OTP_SHIFT) 56 orr r2,r2,r1 57 str r2,[r0,#CC_CLKDIV] /* Update OtpClk in clkdiv with 14 */ 58 ldr r1,=200 /* Wait for 200 cycles for stable OTP clock */ 59spinn: sub r1,r1,#0x1 60 cmp r1,#0x0 61 bne spinn 62 lsr r2,r4,#CC_CAP_OTPSIZE_SHIFT /* Get OTP size */ 63 adrl r1,otp_sizes 64 lsl r2,r2,#0x2 65 ldr r3,[r1,r2] /* Get the OTP size from otp_sizes table (in bytes) */ 66 67 cmp r3,#0x0 /* skip zero size */ 68 beq __hw_init_done 69 ldr r1,[r0,#CC_OTPST] 70 and r1,r1,#OTPS_READY 71 cmp r1,#0x0 /* 0: OTP is not ready for whatever reason */ 72 beq __hw_init_done 73 add r2,r3,r0 /* Seek to the end of OTP region */ 74 /* Scan entire OTP from END -> BEGIN to find first 75 * matching hwinit entry */ 76 sub r2,r2,#2 771: 78 add r4,r2,#CC_SROM_OTP 79 ldrh r1,[r4] 80 lsl r1,r1,#0x10 81 sub r2,r2,#2 82 add r4,r2,#CC_SROM_OTP 83 ldrh r3,[r4] 84 orr r1,r1,r3 85 ldr r4,=0xeaeaeaea /* SID */ 86 cmp r1,r4 87 beq 1f 88 cmp r0,r2 89 blt 1b 90 /* no hwinit data from OTP */ 91 b __hw_init_done 921: 93 add r0,r2,#CC_SROM_OTP 94 add r0,r0,#4 95 mov r1,#0x800 /* for the first delay */ 96 97__init_next_cmd: 98 99 /* 100 * delay for N cycles 101 * read OTP : 32b entry comprise {16b loop count, 8b delay, 8b cmd} 102 * execute OPT cmd. 103 * Do_Next if any. 104 */ 105 106 bl __init_dly /* inter-command delay */ 107 108 ldrh r1,[r0],#2 /* {delay, Cmd} */ 109 and r2,r1,#0x0f /* extract Cmd */ 110 cmp r2,#0x1 /* EID (end of init data) */ 111 beq __hw_init_done /* jump to __hw_init_done on End of Init Data */ 112 ldrh r3,[r0],#2 /* Loop Count */ 113 114 cmp r2,#0 /* NOP */ 115 beq __init_next_cmd 116 117 /* load two 32b datum */ 118 bl __init_load64 119 mov r7,r10 /* prepare indirect addr */ 120 mov r8,r12 /* prepare indirect data */ 121 122 /* 123 * handle various cases 124 */ 125 cmp r2,#4 126 beq __init_wr_dir 127 cmp r2,#5 128 beq __init_wr_indir 129 cmp r2,#6 130 beq __init_wr_indir_incaddr 131 cmp r2,#7 132 beq __init_wr_indir_incaddr 133 cmp r2,#8 134 beq __init_wr_dir_incaddr_data 135 cmp r2,#9 136 beq __init_wr_indir_incaddr_data 137 cmp r2,#10 138 beq __init_wr_dir_incaddr_incdata 139 cmp r2,#11 140 beq __init_wr_indir_incaddr_incdata 141 142 /* write direct (cmd=0x02) is a special case of 143 * write direct multiple (cmd=0x04), under loop count=1 144 145 * write indirect (cmd=0x03) is a special case of 146 * write indirect multiple (cmd=0x05), under loop count=1 147 */ 148 149 /* write direct multiple (cmd=0x04) */ 150__init_wr_dir: 151 str r12,[r10] /* Mem[addr] = data */ 152 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 153 beq __init_next_cmd /* loop cnt = 0 */ 154 bl __init_load64 /* load next pair of addr, data */ 155 bl __init_dly /* inter-op delay */ 156 b __init_wr_dir 157 158 /* write indirect multiple (cmd=0x05) */ 159__init_wr_indir: 160 bl __init_load64 /* load next pair of addr, data */ 161 str r10,[r7] /* mem[indirect addr] = addr */ 162 str r12,[r8] /* mem[indirect data] = data */ 163 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 164 beq __init_next_cmd /* loop cnt = 0 */ 165 bl __init_dly /* inter-op delay */ 166 b __init_wr_indir 167 168 /* cmd=0x06 */ 169 /* write direct, (post) auto-inc address */ 170__init_wr_dir_incaddr: 171 str r12,[r10],#4 /* Mem[addr++] = data, auto-inc addr */ 172 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 173 beq __init_next_cmd /* loop cnt = 0 */ 174 bl __init_load32 /* load next data */ 175 bl __init_dly /* inter-op delay */ 176 b __init_wr_indir_incaddr 177 178 /* cmd=0x07 */ 179 /* write indirect, (post) auto-inc address */ 180__init_wr_indir_incaddr: 181 bl __init_load64 /* load first addr & data */ 182__next_d_0: 183 str r10,[r7] /* Mem[addr] = addr */ 184 str r12,[r8] /* Mem[data] = data */ 185 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 186 beq __init_next_cmd /* loop cnt = 0 */ 187 add r10,r10,#4 /* inc addr by 4 bytes */ 188 bl __init_load32 /* load next data */ 189 bl __init_dly /* inter-op delay */ 190 b __next_d_0 191 192 /* cmd=0x08 */ 193 /* write direct multiple, repeatedly the same data to (post) auto-inc address */ 194__init_wr_dir_incaddr_data: 195 str r12,[r10],#4 /* Mem[addr] = data, auto_inc addr */ 196 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 197 beq __init_next_cmd /* loop cnt = 0 */ 198 bl __init_dly /* inter-op delay */ 199 b __init_wr_dir_incaddr_data 200 201 /* cmd=0x09 */ 202 /* write inirect multiple, repeatedly the same data to (post) auto-inc address */ 203__init_wr_indir_incaddr_data: 204 bl __init_load64 /* load first addr & data */ 205__next_d_1: 206 str r10,[r7] /* Mem[addr] = addr */ 207 str r12,[r8] /* Mem[data] = data */ 208 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 209 beq __init_next_cmd /* loop cnt = 0 */ 210 add r10,r10,#4 /* inc addr by 4 bytes */ 211 bl __init_dly /* inter-op delay */ 212 b __next_d_1 213 214 /* cmd=0x0a */ 215 /* write direct multiple, (post) auto-inc addr and data */ 216__init_wr_dir_incaddr_incdata: 217 str r12,[r10],#4 /* Mem[addr] = data, inc addr */ 218 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 219 beq __init_next_cmd /* loop cnt = 0 */ 220 add r12,r12,#1 /* inc data by 1 */ 221 bl __init_dly /* inter-op delay */ 222 b __init_wr_dir_incaddr_incdata 223 224 /* cmd=0x0b */ 225 /* write indirect multiple, (post) auto-inc addr and data */ 226__init_wr_indir_incaddr_incdata: 227 bl __init_load64 /* load first addr & data */ 228__next_d_2: 229 str r10,[r7] /* Mem[addr] = addr */ 230 str r12,[r8] /* Mem[data] = data */ 231 subs r3,r3,#1 /* loop cnt = loop cnt -1 */ 232 beq __init_next_cmd /* loop cnt = 0 */ 233 add r10,r10,#4 /* inc addr by 4 bytes */ 234 add r12,r12,#1 /* inc data by 1 */ 235 bl __init_dly /* inter-op delay */ 236 b __next_d_2 237 238 /* 239 * Define two Utilities to save the code space. 240 * 241 * load one or two 32b datum from current OTP position 242 * r10 = {r10, r9} 243 * r12 = {r12, r11} 244 */ 245__init_load64: 246 ldrh r10,[r0],#2 247 ldrh r9,[r0],#2 248 orr r10,r9,r10,lsl #16 249__init_load32: 250 ldrh r12,[r0],#2 251 ldrh r11,[r0],#2 252 orr r12,r11,r12,lsl #16 253 bx lr /* return */ 254 255 /* impose some inter-op and inter-cmd delay 256 * delay count is passed thru reg. r1 257 */ 258__init_dly: 259 asr r9,r1,#11 /* r1/8 cycles, effectively (r1&0x0000ff00) >> 3 */ 260 cmp r9,#0 261 beq __no_dly 262__dly_loop: 263 subs r9,r9,#1 /* loop here */ 264 bne __dly_loop 265__no_dly: 266 bx lr /* return */ 267 268 /* 269 * Hardware init. is done 270 */ 271 272__hw_init_done: 273 /* Continuing boot */ 274 mov lr,r6 275 mov pc,lr 276 277/* OTP sizes in bytes */ 278otp_sizes: 279 .word 0 280 .word 256 /* 2048 bits: 32X64 */ 281 .word 512 /* 4096 bits: 2*32X64 */ 282 .word 1024 /* 8192 bits: 4*32X64 */ 283 .word 512 /* 4096 bits: 64X64 */ 284 .word 768 /* 6144 bits: 5 32X64 */ 285 .word 0 /* 512 bits: dont care */ 286 .word 128 /* 1024 bits: 8X64 */ 287 288END(pcie_phy_init) 289