summaryrefslogtreecommitdiff
path: root/arch/arm/mach-ux500/id.c
blob: 4d12f826386853f7f3ebdc9cff62adab5cbdac7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/*
 * Copyright (C) ST-Ericsson SA 2010
 *
 * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
 * License terms: GNU General Public License (GPL) version 2
 */

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/export.h>

#include <asm/cputype.h>
#include <asm/tlbflush.h>
#include <asm/cacheflush.h>
#include <asm/mach/map.h>

#include <mach/hardware.h>
#include <mach/setup.h>

struct dbx500_asic_id dbx500_id;
EXPORT_SYMBOL(dbx500_id);

static unsigned int ux500_read_asicid(phys_addr_t addr)
{
	phys_addr_t base = addr & ~0xfff;
	struct map_desc desc = {
		.virtual	= IO_ADDRESS(base),
		.pfn		= __phys_to_pfn(base),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	};

	iotable_init(&desc, 1);

	/* As in devicemaps_init() */
	local_flush_tlb_all();
	flush_cache_all();

	return readl(__io_address(addr));
}

static unsigned int u9540_read_asicid(phys_addr_t addr)
{
	phys_addr_t base = addr & ~0xfff;
	struct map_desc desc = {
		.virtual	= IO_ADDRESS_DB9540_ROM(base),
		.pfn		= __phys_to_pfn(base),
		.length		= SZ_16K,
		.type		= MT_DEVICE,
	};

	iotable_init(&desc, 1);

	/* As in devicemaps_init() */
	local_flush_tlb_all();
	flush_cache_all();

	return readl(__io_address_db9540_rom(addr));
}

static void ux500_print_soc_info(unsigned int asicid)
{
	unsigned int rev = dbx500_revision();

	pr_info("DB%4x ", dbx500_partnumber());

	if (rev == 0x01)
		pr_cont("Early Drop");
	else if (rev >= 0xA0)
		pr_cont("v%d.%d" , (rev >> 4) - 0xA + 1, rev & 0xf);
	else
		pr_cont("Unknown");

	pr_cont(" [%#010x]\n", asicid);
}

static unsigned int partnumber(unsigned int asicid)
{
	return (asicid >> 8) & 0xffff;
}

/*
 * SOC		MIDR		ASICID ADDRESS		ASICID VALUE
 * DB8500ed	0x410fc090	0x9001FFF4		0x00850001
 * DB8500v1	0x411fc091	0x9001FFF4		0x008500A0
 * DB8500v1.1	0x411fc091	0x9001FFF4		0x008500A1
 * DB8500v2	0x412fc091	0x9001DBF4		0x008500B0
 * DB8520v2.2	0x412fc091	0x9001DBF4		0x008500B2
 * AP9500	0x412fc091	0x9001DBF4		0x008500B2
 * DB5500v1	0x412fc091	0x9001FFF4		0x005500A0
 * DB9540	0x413fc090	0xFFFFDBF4		0x009540xx
 */

void __init ux500_map_io(void)
{
	unsigned int cpuid = read_cpuid_id();
	unsigned int asicid = 0;
	phys_addr_t addr = 0;

	switch (cpuid) {
	case 0x410fc090: /* DB8500ed */
	case 0x411fc091: /* DB8500v1 */
		addr = 0x9001FFF4;
		break;

	case 0x412fc091: /* DB8520 / DB8500v2 / DB5500v1 / AP9500 */
		asicid = ux500_read_asicid(0x9001DBF4);
		if (partnumber(asicid) == 0x8500 ||
		    partnumber(asicid) == 0x8520)
			/* DB8500v2 */
			break;

		/* DB5500v1 */
		addr = 0x9001FFF4;
		break;

	case 0x413fc090: /* DB9540 */
		addr = 0xFFFFDBF4;
		asicid = u9540_read_asicid(addr);
		addr = 0;
		break;
	}

	if (addr)
		asicid = ux500_read_asicid(addr);

	if (!asicid) {
		pr_err("Unable to identify SoC\n");
		ux500_unknown_soc();
	}

	dbx500_id.process = asicid >> 24;
	dbx500_id.partnumber = partnumber(asicid);
	dbx500_id.revision = asicid & 0xff;

	ux500_print_soc_info(asicid);
}