]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
907208c4 CL |
2 | /* |
3 | * (C) Copyright 2000-2002 | |
4 | * Wolfgang Denk, DENX Software Engineering, [email protected]. | |
907208c4 CL |
5 | */ |
6 | ||
7 | /* | |
8 | * m8xx.c | |
9 | * | |
10 | * CPU specific code | |
11 | * | |
12 | * written or collected and sometimes rewritten by | |
13 | * Magnus Damm <[email protected]> | |
14 | * | |
15 | * minor modifications by | |
16 | * Wolfgang Denk <[email protected]> | |
17 | */ | |
18 | ||
19 | #include <common.h> | |
30c7c434 | 20 | #include <cpu_func.h> |
90526e9f | 21 | #include <net.h> |
049f8d6f | 22 | #include <time.h> |
2189d5f1 | 23 | #include <vsprintf.h> |
907208c4 CL |
24 | #include <watchdog.h> |
25 | #include <command.h> | |
26 | #include <mpc8xx.h> | |
907208c4 CL |
27 | #include <netdev.h> |
28 | #include <asm/cache.h> | |
18f8d4c6 | 29 | #include <asm/cpm_8xx.h> |
907208c4 CL |
30 | #include <linux/compiler.h> |
31 | #include <asm/io.h> | |
32 | ||
33 | #if defined(CONFIG_OF_LIBFDT) | |
b08c8c48 | 34 | #include <linux/libfdt.h> |
907208c4 CL |
35 | #include <fdt_support.h> |
36 | #endif | |
37 | ||
38 | DECLARE_GLOBAL_DATA_PTR; | |
39 | ||
907208c4 CL |
40 | /* ------------------------------------------------------------------------- */ |
41 | /* L1 i-cache */ | |
42 | ||
70fd0710 | 43 | int checkicache(void) |
907208c4 | 44 | { |
ba3da734 CL |
45 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
46 | memctl8xx_t __iomem *memctl = &immap->im_memctl; | |
70fd0710 | 47 | u32 cacheon = rd_ic_cst() & IDC_ENABLED; |
ba3da734 CL |
48 | /* probe in flash memoryarea */ |
49 | u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; | |
907208c4 CL |
50 | u32 m; |
51 | u32 lines = -1; | |
52 | ||
70fd0710 CL |
53 | wr_ic_cst(IDC_UNALL); |
54 | wr_ic_cst(IDC_INVALL); | |
55 | wr_ic_cst(IDC_DISABLE); | |
907208c4 CL |
56 | __asm__ volatile ("isync"); |
57 | ||
70fd0710 CL |
58 | while (!((m = rd_ic_cst()) & IDC_CERR2)) { |
59 | wr_ic_adr(k); | |
60 | wr_ic_cst(IDC_LDLCK); | |
907208c4 CL |
61 | __asm__ volatile ("isync"); |
62 | ||
63 | lines++; | |
70fd0710 | 64 | k += 0x10; /* the number of bytes in a cacheline */ |
907208c4 CL |
65 | } |
66 | ||
70fd0710 CL |
67 | wr_ic_cst(IDC_UNALL); |
68 | wr_ic_cst(IDC_INVALL); | |
907208c4 CL |
69 | |
70 | if (cacheon) | |
70fd0710 | 71 | wr_ic_cst(IDC_ENABLE); |
907208c4 | 72 | else |
70fd0710 | 73 | wr_ic_cst(IDC_DISABLE); |
907208c4 CL |
74 | |
75 | __asm__ volatile ("isync"); | |
76 | ||
77 | return lines << 4; | |
78 | }; | |
79 | ||
80 | /* ------------------------------------------------------------------------- */ | |
81 | /* L1 d-cache */ | |
82 | /* call with cache disabled */ | |
83 | ||
3374d28b | 84 | static int checkdcache(void) |
907208c4 | 85 | { |
ba3da734 CL |
86 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
87 | memctl8xx_t __iomem *memctl = &immap->im_memctl; | |
70fd0710 | 88 | u32 cacheon = rd_dc_cst() & IDC_ENABLED; |
ba3da734 CL |
89 | /* probe in flash memoryarea */ |
90 | u32 k = in_be32(&memctl->memc_br0) & ~0x00007fff; | |
907208c4 CL |
91 | u32 m; |
92 | u32 lines = -1; | |
93 | ||
70fd0710 CL |
94 | wr_dc_cst(IDC_UNALL); |
95 | wr_dc_cst(IDC_INVALL); | |
96 | wr_dc_cst(IDC_DISABLE); | |
907208c4 | 97 | |
70fd0710 CL |
98 | while (!((m = rd_dc_cst()) & IDC_CERR2)) { |
99 | wr_dc_adr(k); | |
100 | wr_dc_cst(IDC_LDLCK); | |
907208c4 CL |
101 | lines++; |
102 | k += 0x10; /* the number of bytes in a cacheline */ | |
103 | } | |
104 | ||
70fd0710 CL |
105 | wr_dc_cst(IDC_UNALL); |
106 | wr_dc_cst(IDC_INVALL); | |
907208c4 CL |
107 | |
108 | if (cacheon) | |
70fd0710 | 109 | wr_dc_cst(IDC_ENABLE); |
907208c4 | 110 | else |
70fd0710 | 111 | wr_dc_cst(IDC_DISABLE); |
907208c4 CL |
112 | |
113 | return lines << 4; | |
114 | }; | |
115 | ||
3374d28b SG |
116 | static int check_CPU(long clock, uint pvr, uint immr) |
117 | { | |
118 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; | |
119 | uint k; | |
120 | char buf[32]; | |
121 | ||
122 | /* the highest 16 bits should be 0x0050 for a 860 */ | |
123 | ||
124 | if (PVR_VER(pvr) != PVR_VER(PVR_8xx)) | |
125 | return -1; | |
126 | ||
127 | k = (immr << 16) | | |
128 | in_be16(&immap->im_cpm.cp_dparam16[PROFF_REVNUM / sizeof(u16)]); | |
129 | ||
130 | /* | |
131 | * Some boards use sockets so different CPUs can be used. | |
132 | * We have to check chip version in run time. | |
133 | */ | |
134 | switch (k) { | |
135 | /* MPC866P/MPC866T/MPC859T/MPC859DSL/MPC852T */ | |
136 | case 0x08010004: /* Rev. A.0 */ | |
137 | printf("MPC866xxxZPnnA"); | |
138 | break; | |
139 | case 0x08000003: /* Rev. 0.3 */ | |
140 | printf("MPC866xxxZPnn"); | |
141 | break; | |
142 | case 0x09000000: /* 870/875/880/885 */ | |
143 | puts("MPC885ZPnn"); | |
144 | break; | |
145 | ||
146 | default: | |
147 | printf("unknown MPC86x (0x%08x)", k); | |
148 | break; | |
149 | } | |
150 | ||
151 | printf(" at %s MHz: ", strmhz(buf, clock)); | |
152 | ||
153 | print_size(checkicache(), " I-Cache "); | |
154 | print_size(checkdcache(), " D-Cache"); | |
155 | ||
156 | /* do we have a FEC (860T/P or 852/859/866/885)? */ | |
157 | ||
158 | out_be32(&immap->im_cpm.cp_fec.fec_addr_low, 0x12345678); | |
159 | if (in_be32(&immap->im_cpm.cp_fec.fec_addr_low) == 0x12345678) | |
160 | printf(" FEC present"); | |
161 | ||
162 | putc('\n'); | |
163 | ||
164 | return 0; | |
165 | } | |
166 | ||
167 | /* ------------------------------------------------------------------------- */ | |
168 | ||
169 | int checkcpu(void) | |
170 | { | |
171 | ulong clock = gd->cpu_clk; | |
172 | uint immr = get_immr(); /* Return full IMMR contents */ | |
173 | uint pvr = get_pvr(); | |
174 | ||
175 | puts("CPU: "); | |
176 | ||
177 | return check_CPU(clock, pvr, immr); | |
178 | } | |
179 | ||
907208c4 CL |
180 | /* ------------------------------------------------------------------------- */ |
181 | ||
70fd0710 | 182 | void upmconfig(uint upm, uint *table, uint size) |
907208c4 CL |
183 | { |
184 | uint i; | |
185 | uint addr = 0; | |
ba3da734 CL |
186 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
187 | memctl8xx_t __iomem *memctl = &immap->im_memctl; | |
907208c4 CL |
188 | |
189 | for (i = 0; i < size; i++) { | |
ba3da734 CL |
190 | out_be32(&memctl->memc_mdr, table[i]); /* (16-15) */ |
191 | out_be32(&memctl->memc_mcr, addr | upm); /* (16-16) */ | |
907208c4 CL |
192 | addr++; |
193 | } | |
194 | } | |
195 | ||
196 | /* ------------------------------------------------------------------------- */ | |
197 | ||
70fd0710 | 198 | int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) |
907208c4 CL |
199 | { |
200 | ulong msr, addr; | |
201 | ||
ba3da734 | 202 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
907208c4 | 203 | |
ba3da734 CL |
204 | /* Checkstop Reset enable */ |
205 | setbits_be32(&immap->im_clkrst.car_plprcr, PLPRCR_CSR); | |
907208c4 CL |
206 | |
207 | /* Interrupts and MMU off */ | |
208 | __asm__ volatile ("mtspr 81, 0"); | |
70fd0710 | 209 | __asm__ volatile ("mfmsr %0" : "=r" (msr)); |
907208c4 CL |
210 | |
211 | msr &= ~0x1030; | |
70fd0710 | 212 | __asm__ volatile ("mtmsr %0" : : "r" (msr)); |
907208c4 CL |
213 | |
214 | /* | |
215 | * Trying to execute the next instruction at a non-existing address | |
216 | * should cause a machine check, resulting in reset | |
217 | */ | |
218 | #ifdef CONFIG_SYS_RESET_ADDRESS | |
219 | addr = CONFIG_SYS_RESET_ADDRESS; | |
220 | #else | |
221 | /* | |
70fd0710 CL |
222 | * note: when CONFIG_SYS_MONITOR_BASE points to a RAM address, |
223 | * CONFIG_SYS_MONITOR_BASE - sizeof (ulong) is usually a valid address. | |
224 | * Better pick an address known to be invalid on your system and assign | |
225 | * it to CONFIG_SYS_RESET_ADDRESS. | |
907208c4 CL |
226 | * "(ulong)-1" used to be a good choice for many systems... |
227 | */ | |
70fd0710 | 228 | addr = CONFIG_SYS_MONITOR_BASE - sizeof(ulong); |
907208c4 | 229 | #endif |
70fd0710 | 230 | ((void (*)(void)) addr)(); |
907208c4 CL |
231 | return 1; |
232 | } | |
233 | ||
234 | /* ------------------------------------------------------------------------- */ | |
235 | ||
236 | /* | |
237 | * Get timebase clock frequency (like cpu_clk in Hz) | |
238 | * | |
239 | * See sections 14.2 and 14.6 of the User's Manual | |
240 | */ | |
70fd0710 | 241 | unsigned long get_tbclk(void) |
907208c4 | 242 | { |
374a0e30 | 243 | immap_t __iomem *immap = (immap_t __iomem *)CONFIG_SYS_IMMR; |
907208c4 CL |
244 | ulong oscclk, factor, pll; |
245 | ||
ba3da734 | 246 | if (in_be32(&immap->im_clkrst.car_sccr) & SCCR_TBS) |
70fd0710 | 247 | return gd->cpu_clk / 16; |
907208c4 | 248 | |
ba3da734 | 249 | pll = in_be32(&immap->im_clkrst.car_plprcr); |
907208c4 CL |
250 | |
251 | #define PLPRCR_val(a) ((pll & PLPRCR_ ## a ## _MSK) >> PLPRCR_ ## a ## _SHIFT) | |
252 | ||
253 | /* | |
254 | * For newer PQ1 chips (MPC866/87x/88x families), PLL multiplication | |
255 | * factor is calculated as follows: | |
256 | * | |
257 | * MFN | |
258 | * MFI + ------- | |
259 | * MFD + 1 | |
260 | * factor = ----------------- | |
261 | * (PDF + 1) * 2^S | |
262 | * | |
263 | */ | |
70fd0710 CL |
264 | factor = (PLPRCR_val(MFI) + PLPRCR_val(MFN) / (PLPRCR_val(MFD) + 1)) / |
265 | (PLPRCR_val(PDF) + 1) / (1 << PLPRCR_val(S)); | |
907208c4 CL |
266 | |
267 | oscclk = gd->cpu_clk / factor; | |
268 | ||
ba3da734 CL |
269 | if ((in_be32(&immap->im_clkrst.car_sccr) & SCCR_RTSEL) == 0 || |
270 | factor > 2) | |
70fd0710 | 271 | return oscclk / 4; |
ba3da734 | 272 | |
70fd0710 | 273 | return oscclk / 16; |
907208c4 CL |
274 | } |
275 | ||
907208c4 CL |
276 | /* |
277 | * Initializes on-chip ethernet controllers. | |
278 | * to override, implement board_eth_init() | |
279 | */ | |
280 | int cpu_eth_init(bd_t *bis) | |
281 | { | |
fad51ac3 | 282 | #if defined(CONFIG_MPC8XX_FEC) |
907208c4 CL |
283 | fec_initialize(bis); |
284 | #endif | |
285 | return 0; | |
286 | } |