summaryrefslogtreecommitdiffstats
path: root/arch/arm/boards/zii-vf610-dev/lowlevel.c
blob: 95b68d5dcea3fddab14cc763bd0c6f0017660c35 (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
/*
 * Copyright (C) 2016 Zodiac Inflight Innovation
 * Author: Andrey Smirnov <andrew.smirnov@gmail.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <common.h>
#include <linux/sizes.h>
#include <mach/generic.h>
#include <asm/barebox-arm-head.h>
#include <asm/barebox-arm.h>
#include <mach/vf610-regs.h>
#include <mach/clock-vf610.h>
#include <mach/iomux-vf610.h>
#include <debug_ll.h>

static inline void setup_uart(void)
{
	void __iomem *iomux = IOMEM(VF610_IOMUXC_BASE_ADDR);

	vf610_ungate_all_peripherals();
	vf610_setup_pad(iomux, VF610_PAD_PTB10__UART0_TX);
	vf610_uart_setup_ll();

	putc_ll('>');
}

enum zii_platform_vf610_type {
	ZII_PLATFORM_VF610_DEV_REV_B	= 0x01,
	ZII_PLATFORM_VF610_SCU4_AIB	= 0x02,
	ZII_PLATFORM_VF610_SPU3		= 0x03,
	ZII_PLATFORM_VF610_CFU1		= 0x04,
	ZII_PLATFORM_VF610_DEV_REV_C	= 0x05,
};

unsigned int get_system_type(void)
{
#define GPIO_PDIR 0x10

	u32 pdir;
	void __iomem *gpio2 = IOMEM(VF610_GPIO2_BASE_ADDR);
	void __iomem *iomux = IOMEM(VF610_IOMUXC_BASE_ADDR);
	unsigned low, high;

	/*
	 * System type is encoded as a 4-bit number specified by the
	 * following pins (pulled up or down with resistors on the
	 * board).
	*/
	vf610_setup_pad(iomux, VF610_PAD_PTD16__GPIO_78);
	vf610_setup_pad(iomux, VF610_PAD_PTD17__GPIO_77);
	vf610_setup_pad(iomux, VF610_PAD_PTD18__GPIO_76);
	vf610_setup_pad(iomux, VF610_PAD_PTD19__GPIO_75);

	pdir = readl(gpio2 + GPIO_PDIR);

	low  = 75 % 32;
	high = 78 % 32;

	pdir &= GENMASK(high, low);
	pdir >>= low;

	return pdir;
}

extern char __dtb_vf610_zii_dev_rev_b_start[];
extern char __dtb_vf610_zii_dev_rev_c_start[];
extern char __dtb_vf610_zii_cfu1_rev_a_start[];
extern char __dtb_vf610_zii_spu3_rev_a_start[];
extern char __dtb_vf610_zii_scu4_aib_rev_c_start[];

ENTRY_FUNCTION(start_zii_vf610_dev, r0, r1, r2)
{
	void *fdt;
	const unsigned int system_type = get_system_type();

	vf610_cpu_lowlevel_init();

	if (IS_ENABLED(CONFIG_DEBUG_LL))
		setup_uart();

	switch (system_type) {
	default:
		/*
		 * GCC can be smart enough to, when DEBUG_LL is
		 * disabled, reduce this switch statement to a LUT
		 * fetch. Unfortunately here, this early in the boot
		 * process before any relocation/address fixups could
		 * happen, the address of that LUT used by the code is
		 * incorrect and any access to it would result in
		 * bogus values.
		 *
		 * Adding the following barrier() statement seem to
		 * force the compiler to always translate this block
		 * to a sequence of consecutive checks and jumps with
		 * relative fetches, which should work with or without
		 * relocation/fixups.
		 */
		barrier();

		if (IS_ENABLED(CONFIG_DEBUG_LL)) {
			relocate_to_current_adr();
			setup_c();
			puts_ll("*********************************\n");
			puts_ll("* Unknown system type: ");
			puthex_ll(system_type);
			puts_ll("\n* Assuming devboard revision B\n");
			puts_ll("*********************************\n");
		}
	case ZII_PLATFORM_VF610_DEV_REV_B: /* FALLTHROUGH */
		fdt = __dtb_vf610_zii_dev_rev_b_start;
		break;
	case ZII_PLATFORM_VF610_SCU4_AIB:
		fdt = __dtb_vf610_zii_scu4_aib_rev_c_start;
		break;
	case ZII_PLATFORM_VF610_DEV_REV_C:
		fdt = __dtb_vf610_zii_dev_rev_c_start;
		break;
	case ZII_PLATFORM_VF610_CFU1:
		fdt = __dtb_vf610_zii_cfu1_rev_a_start;
		break;
	case ZII_PLATFORM_VF610_SPU3:
		fdt = __dtb_vf610_zii_spu3_rev_a_start;
		break;
	}

	barebox_arm_entry(0x80000000, SZ_512M, fdt - get_runtime_offset());
}