Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
c6x
kernel
setup.c
Go to the documentation of this file.
1
/*
2
* Port on Texas Instruments TMS320C6x architecture
3
*
4
* Copyright (C) 2004, 2006, 2009, 2010, 2011 Texas Instruments Incorporated
5
* Author: Aurelien Jacquiot (
[email protected]
)
6
*
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License version 2 as
9
* published by the Free Software Foundation.
10
*/
11
#include <
linux/dma-mapping.h
>
12
#include <
linux/memblock.h
>
13
#include <
linux/seq_file.h
>
14
#include <
linux/bootmem.h
>
15
#include <
linux/clkdev.h
>
16
#include <
linux/initrd.h
>
17
#include <linux/kernel.h>
18
#include <linux/module.h>
19
#include <
linux/of_fdt.h
>
20
#include <linux/string.h>
21
#include <linux/errno.h>
22
#include <
linux/cache.h
>
23
#include <
linux/delay.h
>
24
#include <linux/sched.h>
25
#include <
linux/clk.h
>
26
#include <
linux/cpu.h
>
27
#include <linux/fs.h>
28
#include <
linux/of.h
>
29
30
31
#include <asm/sections.h>
32
#include <asm/div64.h>
33
#include <asm/setup.h>
34
#include <
asm/dscr.h
>
35
#include <asm/clock.h>
36
#include <
asm/soc.h
>
37
#include <asm/special_insns.h>
38
39
static
const
char
*c6x_soc_name;
40
41
int
c6x_num_cores
;
42
EXPORT_SYMBOL_GPL
(
c6x_num_cores
);
43
44
unsigned
int
c6x_silicon_rev
;
45
EXPORT_SYMBOL_GPL
(
c6x_silicon_rev
);
46
47
/*
48
* Device status register. This holds information
49
* about device configuration needed by some drivers.
50
*/
51
unsigned
int
c6x_devstat
;
52
EXPORT_SYMBOL_GPL
(
c6x_devstat
);
53
54
/*
55
* Some SoCs have fuse registers holding a unique MAC
56
* address. This is parsed out of the device tree with
57
* the resulting MAC being held here.
58
*/
59
unsigned
char
c6x_fuse_mac
[6];
60
61
unsigned
long
memory_start
;
62
unsigned
long
memory_end
;
63
64
unsigned
long
ram_start
;
65
unsigned
long
ram_end
;
66
67
/* Uncached memory for DMA consistent use (memdma=) */
68
static
unsigned
long
dma_start
__initdata
;
69
static
unsigned
long
dma_size
__initdata
;
70
71
char
c6x_command_line
[
COMMAND_LINE_SIZE
];
72
73
#if defined(CONFIG_CMDLINE_BOOL)
74
static
const
char
default_command_line[
COMMAND_LINE_SIZE
]
__section
(.
cmdline
) =
75
CONFIG_CMDLINE;
76
#endif
77
78
struct
cpuinfo_c6x
{
79
const
char
*
cpu_name
;
80
const
char
*
cpu_voltage
;
81
const
char
*
mmu
;
82
const
char
*
fpu
;
83
char
*
cpu_rev
;
84
unsigned
int
core_id
;
85
char
__cpu_rev
[5];
86
};
87
88
static
DEFINE_PER_CPU
(
struct
cpuinfo_c6x
,
cpu_data
);
89
90
unsigned
int
ticks_per_ns_scaled
;
91
EXPORT_SYMBOL
(
ticks_per_ns_scaled
);
92
93
unsigned
int
c6x_core_freq
;
94
95
static
void
__init
get_cpuinfo
(
void
)
96
{
97
unsigned
cpu_id
, rev_id,
csr
;
98
struct
clk
*coreclk =
clk_get_sys
(
NULL
,
"core"
);
99
unsigned
long
core_khz;
100
u64
tmp
;
101
struct
cpuinfo_c6x
*
p
;
102
struct
device_node
*
node
, *np;
103
104
p = &
per_cpu
(
cpu_data
,
smp_processor_id
());
105
106
if
(!IS_ERR(coreclk))
107
c6x_core_freq
=
clk_get_rate
(coreclk);
108
else
{
109
printk
(
KERN_WARNING
110
"Cannot find core clock frequency. Using 700MHz\n"
);
111
c6x_core_freq
= 700000000;
112
}
113
114
core_khz =
c6x_core_freq
/ 1000;
115
116
tmp = (
uint64_t
)core_khz <<
C6X_NDELAY_SCALE
;
117
do_div
(tmp, 1000000);
118
ticks_per_ns_scaled
=
tmp
;
119
120
csr =
get_creg
(
CSR
);
121
cpu_id = csr >> 24;
122
rev_id = (csr >> 16) & 0xff;
123
124
p->
mmu
=
"none"
;
125
p->
fpu
=
"none"
;
126
p->
cpu_voltage
=
"unknown"
;
127
128
switch
(cpu_id) {
129
case
0:
130
p->
cpu_name
=
"C67x"
;
131
p->
fpu
=
"yes"
;
132
break
;
133
case
2:
134
p->
cpu_name
=
"C62x"
;
135
break
;
136
case
8:
137
p->
cpu_name
=
"C64x"
;
138
break
;
139
case
12:
140
p->
cpu_name
=
"C64x"
;
141
break
;
142
case
16:
143
p->
cpu_name
=
"C64x+"
;
144
p->
cpu_voltage
=
"1.2"
;
145
break
;
146
case
21:
147
p->
cpu_name
=
"C66X"
;
148
p->
cpu_voltage
=
"1.2"
;
149
break
;
150
default
:
151
p->
cpu_name
=
"unknown"
;
152
break
;
153
}
154
155
if
(cpu_id < 16) {
156
switch
(rev_id) {
157
case
0x1:
158
if
(cpu_id > 8) {
159
p->
cpu_rev
=
"DM640/DM641/DM642/DM643"
;
160
p->
cpu_voltage
=
"1.2 - 1.4"
;
161
}
else
{
162
p->
cpu_rev
=
"C6201"
;
163
p->
cpu_voltage
=
"2.5"
;
164
}
165
break
;
166
case
0x2:
167
p->
cpu_rev
=
"C6201B/C6202/C6211"
;
168
p->
cpu_voltage
=
"1.8"
;
169
break
;
170
case
0x3:
171
p->
cpu_rev
=
"C6202B/C6203/C6204/C6205"
;
172
p->
cpu_voltage
=
"1.5"
;
173
break
;
174
case
0x201:
175
p->
cpu_rev
=
"C6701 revision 0 (early CPU)"
;
176
p->
cpu_voltage
=
"1.8"
;
177
break
;
178
case
0x202:
179
p->
cpu_rev
=
"C6701/C6711/C6712"
;
180
p->
cpu_voltage
=
"1.8"
;
181
break
;
182
case
0x801:
183
p->
cpu_rev
=
"C64x"
;
184
p->
cpu_voltage
=
"1.5"
;
185
break
;
186
default
:
187
p->
cpu_rev
=
"unknown"
;
188
}
189
}
else
{
190
p->
cpu_rev
= p->
__cpu_rev
;
191
snprintf
(p->
__cpu_rev
,
sizeof
(p->
__cpu_rev
),
"0x%x"
, cpu_id);
192
}
193
194
p->
core_id
=
get_coreid
();
195
196
node =
of_find_node_by_name
(
NULL
,
"cpus"
);
197
if
(node) {
198
for_each_child_of_node
(node, np)
199
if
(!
strcmp
(
"cpu"
, np->
name
))
200
++
c6x_num_cores
;
201
of_node_put(node);
202
}
203
204
node =
of_find_node_by_name
(
NULL
,
"soc"
);
205
if
(node) {
206
if
(
of_property_read_string
(node,
"model"
, &c6x_soc_name))
207
c6x_soc_name =
"unknown"
;
208
of_node_put(node);
209
}
else
210
c6x_soc_name =
"unknown"
;
211
212
printk
(
KERN_INFO
"CPU%d: %s rev %s, %s volts, %uMHz\n"
,
213
p->
core_id
, p->
cpu_name
, p->
cpu_rev
,
214
p->
cpu_voltage
,
c6x_core_freq
/ 1000000);
215
}
216
217
/*
218
* Early parsing of the command line
219
*/
220
static
u32
mem_size
__initdata
;
221
222
/* "mem=" parsing. */
223
static
int
__init
early_mem(
char
*
p
)
224
{
225
if
(!p)
226
return
-
EINVAL
;
227
228
mem_size
=
memparse
(p, &p);
229
/* don't remove all of memory when handling "mem={invalid}" */
230
if
(
mem_size
== 0)
231
return
-
EINVAL
;
232
233
return
0;
234
}
235
early_param
(
"mem"
, early_mem);
236
237
/* "memdma=<size>[@<address>]" parsing. */
238
static
int
__init
early_memdma(
char
*p)
239
{
240
if
(!p)
241
return
-
EINVAL
;
242
243
dma_size =
memparse
(p, &p);
244
if
(*p ==
'@'
)
245
dma_start
=
memparse
(p, &p);
246
247
return
0;
248
}
249
early_param
(
"memdma"
, early_memdma);
250
251
int
__init
c6x_add_memory
(
phys_addr_t
start
,
unsigned
long
size
)
252
{
253
static
int
ram_found
__initdata
;
254
255
/* We only handle one bank (the one with PAGE_OFFSET) for now */
256
if
(ram_found)
257
return
-
EINVAL
;
258
259
if
(start >
PAGE_OFFSET
||
PAGE_OFFSET
>= (start + size))
260
return
0;
261
262
ram_start
=
start
;
263
ram_end
= start +
size
;
264
265
ram_found = 1;
266
return
0;
267
}
268
269
/*
270
* Do early machine setup and device tree parsing. This is called very
271
* early on the boot process.
272
*/
273
notrace
void
__init
machine_init
(
unsigned
long
dt_ptr)
274
{
275
struct
boot_param_header
*dtb =
__va
(dt_ptr);
276
struct
boot_param_header
*fdt = (
struct
boot_param_header
*)
_fdt_start
;
277
278
/* interrupts must be masked */
279
set_creg
(
IER
, 2);
280
281
/*
282
* Set the Interrupt Service Table (IST) to the beginning of the
283
* vector table.
284
*/
285
set_ist
(
_vectors_start
);
286
287
lockdep_init
();
288
289
/*
290
* dtb is passed in from bootloader.
291
* fdt is linked in blob.
292
*/
293
if
(dtb && dtb != fdt)
294
fdt = dtb;
295
296
/* Do some early initialization based on the flat device tree */
297
early_init_devtree
(fdt);
298
299
/* parse_early_param needs a boot_command_line */
300
strlcpy
(
boot_command_line
,
c6x_command_line
,
COMMAND_LINE_SIZE
);
301
parse_early_param
();
302
}
303
304
void
__init
setup_arch
(
char
**cmdline_p)
305
{
306
int
bootmap_size;
307
struct
memblock_region *
reg
;
308
309
printk
(
KERN_INFO
"Initializing kernel\n"
);
310
311
/* Initialize command line */
312
*cmdline_p =
c6x_command_line
;
313
314
memory_end
=
ram_end
;
315
memory_end
&= ~(
PAGE_SIZE
- 1);
316
317
if
(
mem_size
&& (
PAGE_OFFSET
+
PAGE_ALIGN
(
mem_size
)) <
memory_end
)
318
memory_end
=
PAGE_OFFSET
+
PAGE_ALIGN
(
mem_size
);
319
320
/* add block that this kernel can use */
321
memblock_add
(
PAGE_OFFSET
,
memory_end
-
PAGE_OFFSET
);
322
323
/* reserve kernel text/data/bss */
324
memblock_reserve
(
PAGE_OFFSET
,
325
PAGE_ALIGN
((
unsigned
long
)&
_end
-
PAGE_OFFSET
));
326
327
if
(dma_size) {
328
/* align to cacheability granularity */
329
dma_size =
CACHE_REGION_END
(dma_size);
330
331
if
(!
dma_start
)
332
dma_start
=
memory_end
- dma_size;
333
334
/* align to cacheability granularity */
335
dma_start
=
CACHE_REGION_START
(
dma_start
);
336
337
/* reserve DMA memory taken from kernel memory */
338
if
(
memblock_is_region_memory
(
dma_start
, dma_size))
339
memblock_reserve
(
dma_start
, dma_size);
340
}
341
342
memory_start
=
PAGE_ALIGN
((
unsigned
int
) &
_end
);
343
344
printk
(
KERN_INFO
"Memory Start=%08lx, Memory End=%08lx\n"
,
345
memory_start
,
memory_end
);
346
347
#ifdef CONFIG_BLK_DEV_INITRD
348
/*
349
* Reserve initrd memory if in kernel memory.
350
*/
351
if
(
initrd_start
<
initrd_end
)
352
if
(
memblock_is_region_memory
(
initrd_start
,
353
initrd_end
-
initrd_start
))
354
memblock_reserve
(
initrd_start
,
355
initrd_end
-
initrd_start
);
356
#endif
357
358
init_mm
.start_code = (
unsigned
long
) &
_stext
;
359
init_mm
.end_code = (
unsigned
long
) &
_etext
;
360
init_mm
.end_data =
memory_start
;
361
init_mm
.brk =
memory_start
;
362
363
/*
364
* Give all the memory to the bootmap allocator, tell it to put the
365
* boot mem_map at the start of memory
366
*/
367
bootmap_size =
init_bootmem_node
(
NODE_DATA
(0),
368
memory_start
>>
PAGE_SHIFT
,
369
PAGE_OFFSET
>>
PAGE_SHIFT
,
370
memory_end
>>
PAGE_SHIFT
);
371
memblock_reserve
(
memory_start
, bootmap_size);
372
373
unflatten_device_tree();
374
375
c6x_cache_init
();
376
377
/* Set the whole external memory as non-cacheable */
378
disable_caching
(
ram_start
,
ram_end
- 1);
379
380
/* Set caching of external RAM used by Linux */
381
for_each_memblock(
memory
, reg)
382
enable_caching
(
CACHE_REGION_START
(reg->base),
383
CACHE_REGION_START
(reg->base + reg->size - 1));
384
385
#ifdef CONFIG_BLK_DEV_INITRD
386
/*
387
* Enable caching for initrd which falls outside kernel memory.
388
*/
389
if
(
initrd_start
<
initrd_end
) {
390
if
(!
memblock_is_region_memory
(
initrd_start
,
391
initrd_end
-
initrd_start
))
392
enable_caching
(
CACHE_REGION_START
(
initrd_start
),
393
CACHE_REGION_START
(
initrd_end
- 1));
394
}
395
#endif
396
397
/*
398
* Disable caching for dma coherent memory taken from kernel memory.
399
*/
400
if
(dma_size &&
memblock_is_region_memory
(
dma_start
, dma_size))
401
disable_caching
(
dma_start
,
402
CACHE_REGION_START
(
dma_start
+ dma_size - 1));
403
404
/* Initialize the coherent memory allocator */
405
coherent_mem_init
(
dma_start
, dma_size);
406
407
/*
408
* Free all memory as a starting point.
409
*/
410
free_bootmem
(
PAGE_OFFSET
,
memory_end
-
PAGE_OFFSET
);
411
412
/*
413
* Then reserve memory which is already being used.
414
*/
415
for_each_memblock(
reserved
, reg) {
416
pr_debug
(
"reserved - 0x%08x-0x%08x\n"
,
417
(
u32
) reg->base, (
u32
) reg->size);
418
reserve_bootmem
(reg->base, reg->size,
BOOTMEM_DEFAULT
);
419
}
420
421
max_low_pfn
=
PFN_DOWN
(
memory_end
);
422
min_low_pfn
=
PFN_UP
(
memory_start
);
423
max_mapnr
=
max_low_pfn
-
min_low_pfn
;
424
425
/* Get kmalloc into gear */
426
paging_init
();
427
428
/*
429
* Probe for Device State Configuration Registers.
430
* We have to do this early in case timer needs to be enabled
431
* through DSCR.
432
*/
433
dscr_probe
();
434
435
/* We do this early for timer and core clock frequency */
436
c64x_setup_clocks
();
437
438
/* Get CPU info */
439
get_cpuinfo
();
440
441
#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
442
conswitchp
= &
dummy_con
;
443
#endif
444
}
445
446
#define cpu_to_ptr(n) ((void *)((long)(n)+1))
447
#define ptr_to_cpu(p) ((long)(p) - 1)
448
449
static
int
show_cpuinfo(
struct
seq_file
*
m
,
void
*
v
)
450
{
451
int
n
=
ptr_to_cpu
(v);
452
struct
cpuinfo_c6x
*p = &
per_cpu
(
cpu_data
, n);
453
454
if
(n == 0) {
455
seq_printf
(m,
456
"soc\t\t: %s\n"
457
"soc revision\t: 0x%x\n"
458
"soc cores\t: %d\n"
,
459
c6x_soc_name,
c6x_silicon_rev
,
c6x_num_cores
);
460
}
461
462
seq_printf
(m,
463
"\n"
464
"processor\t: %d\n"
465
"cpu\t\t: %s\n"
466
"core revision\t: %s\n"
467
"core voltage\t: %s\n"
468
"core id\t\t: %d\n"
469
"mmu\t\t: %s\n"
470
"fpu\t\t: %s\n"
471
"cpu MHz\t\t: %u\n"
472
"bogomips\t: %lu.%02lu\n\n"
,
473
n,
474
p->
cpu_name
, p->
cpu_rev
, p->
cpu_voltage
,
475
p->
core_id
, p->
mmu
, p->
fpu
,
476
(
c6x_core_freq
+ 500000) / 1000000,
477
(
loops_per_jiffy
/(500000/
HZ
)),
478
(
loops_per_jiffy
/(5000/
HZ
))%100);
479
480
return
0;
481
}
482
483
static
void
*
c_start
(
struct
seq_file
*
m
, loff_t *
pos
)
484
{
485
return
*pos <
nr_cpu_ids
?
cpu_to_ptr
(*pos) :
NULL
;
486
}
487
static
void
*c_next(
struct
seq_file
*m,
void
*
v
, loff_t *pos)
488
{
489
++*
pos
;
490
return
NULL
;
491
}
492
static
void
c_stop(
struct
seq_file
*m,
void
*
v
)
493
{
494
}
495
496
const
struct
seq_operations
cpuinfo_op
= {
497
c_start
,
498
c_stop,
499
c_next,
500
show_cpuinfo
501
};
502
503
static
struct
cpu
cpu_devices[
NR_CPUS
];
504
505
static
int
__init
topology_init(
void
)
506
{
507
int
i
;
508
509
for_each_present_cpu
(i)
510
register_cpu
(&cpu_devices[i], i);
511
512
return
0;
513
}
514
515
subsys_initcall
(topology_init);
Generated on Thu Jan 10 2013 12:52:43 for Linux Kernel by
1.8.2