summaryrefslogtreecommitdiff
path: root/board/matrix_vision/mvblx/fpga.c
blob: 7f9b24550597888c342b9cb5e9b66ec63cbd75b6 (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/*
 * (C) Copyright 2002
 * Rich Ireland, Enterasys Networks, rireland@enterasys.com.
 * Keith Outwater, keith_outwater@mvis.com.
 *
 * (C) Copyright 2011
 * Andre Schwarz, Matrix Vision GmbH, andre.schwarz@matrix-vision.de
 * Michael Jones, Matrix Vision GmbH, michael.jones@matrix-vision.de
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <ACEX1K.h>
#include <command.h>
#include <asm/gpio.h>
#include <linux/byteorder/generic.h>
#include "fpga.h"

#ifdef FPGA_DEBUG
#define fpga_debug(fmt, args...)      printf("%s: "fmt, __func__, ##args)
#else
#define fpga_debug(fmt, args...)
#endif

Altera_CYC2_Passive_Serial_fns altera_fns = {
	fpga_null_fn,   /* Altera_pre_fn */
	fpga_config_fn,
	fpga_status_fn,
	fpga_done_fn,
	fpga_wr_fn,
	fpga_null_fn,
	fpga_null_fn,
};

Altera_desc cyclone2 = {
	Altera_CYC2,
	fast_passive_parallel,
	Altera_EP3C5_SIZE,
	(void *) &altera_fns,
	NULL,
	0
};

#define GPIO_RESET		43
#define GPIO_DCLK		65
#define GPIO_nSTATUS	157
#define GPIO_CONF_DONE	158
#define GPIO_nCONFIG	159
#define GPIO_DATA0		54
#define GPIO_DATA1		55
#define GPIO_DATA2		56
#define GPIO_DATA3		57
#define GPIO_DATA4		58
#define GPIO_DATA5		60
#define GPIO_DATA6		61
#define GPIO_DATA7		62

DECLARE_GLOBAL_DATA_PTR;

/* return FPGA_SUCCESS on success, else FPGA_FAIL
 */
int mvblx_init_fpga(void)
{
	fpga_debug("Initializing FPGA interface\n");
	fpga_init();
	fpga_add(fpga_altera, &cyclone2);

	if (gpio_request(GPIO_DCLK, "dclk") ||
			gpio_request(GPIO_nSTATUS, "nStatus") ||
#ifndef CONFIG_SYS_FPGA_DONT_USE_CONF_DONE
			gpio_request(GPIO_CONF_DONE, "conf_done") ||
#endif
			gpio_request(GPIO_nCONFIG, "nConfig") ||
			gpio_request(GPIO_DATA0, "data0") ||
			gpio_request(GPIO_DATA1, "data1") ||
			gpio_request(GPIO_DATA2, "data2") ||
			gpio_request(GPIO_DATA3, "data3") ||
			gpio_request(GPIO_DATA4, "data4") ||
			gpio_request(GPIO_DATA5, "data5") ||
			gpio_request(GPIO_DATA6, "data6") ||
			gpio_request(GPIO_DATA7, "data7")) {
		printf("%s: error requesting GPIOs.", __func__);
		return FPGA_FAIL;
	}

	/* set up outputs */
	gpio_direction_output(GPIO_DCLK,  0);
	gpio_direction_output(GPIO_nCONFIG, 0);
	gpio_direction_output(GPIO_DATA0, 0);
	gpio_direction_output(GPIO_DATA1, 0);
	gpio_direction_output(GPIO_DATA2, 0);
	gpio_direction_output(GPIO_DATA3, 0);
	gpio_direction_output(GPIO_DATA4, 0);
	gpio_direction_output(GPIO_DATA5, 0);
	gpio_direction_output(GPIO_DATA6, 0);
	gpio_direction_output(GPIO_DATA7, 0);

	/* NB omap_free_gpio() resets to an input, so we can't
	 * free ie. nCONFIG, or else the FPGA would reset
	 * Q: presumably gpio_free() has the same effect?
	 */

	/* set up inputs */
	gpio_direction_input(GPIO_nSTATUS);
#ifndef CONFIG_SYS_FPGA_DONT_USE_CONF_DONE
	gpio_direction_input(GPIO_CONF_DONE);
#endif

	fpga_config_fn(0, 1, 0);
	udelay(60);

	return FPGA_SUCCESS;
}

int fpga_null_fn(int cookie)
{
	return 0;
}

int fpga_config_fn(int assert, int flush, int cookie)
{
	fpga_debug("SET config : %s=%d\n", assert ? "low" : "high", assert);
	if (flush) {
		gpio_set_value(GPIO_nCONFIG, !assert);
		udelay(1);
		gpio_set_value(GPIO_nCONFIG, assert);
	}

	return assert;
}

int fpga_done_fn(int cookie)
{
	int result = 0;

	/* since revA of BLX, we will not get this signal. */
	udelay(10);
#ifdef CONFIG_SYS_FPGA_DONT_USE_CONF_DONE
	fpga_debug("not waiting for CONF_DONE.");
	result = 1;
#else
	fpga_debug("CONF_DONE check ... ");
	if (gpio_get_value(GPIO_CONF_DONE))  {
		fpga_debug("high\n");
		result = 1;
	} else
		fpga_debug("low\n");
	gpio_free(GPIO_CONF_DONE);
#endif

	return result;
}

int fpga_status_fn(int cookie)
{
	int result = 0;
	fpga_debug("STATUS check ... ");

	result = gpio_get_value(GPIO_nSTATUS);

	if (result < 0)
		fpga_debug("error\n");
	else if (result > 0)
		fpga_debug("high\n");
	else
		fpga_debug("low\n");

	return result;
}

static inline int _write_fpga(u8 byte)
{
	gpio_set_value(GPIO_DATA0, byte & 0x01);
	gpio_set_value(GPIO_DATA1, (byte >> 1) & 0x01);
	gpio_set_value(GPIO_DATA2, (byte >> 2) & 0x01);
	gpio_set_value(GPIO_DATA3, (byte >> 3) & 0x01);
	gpio_set_value(GPIO_DATA4, (byte >> 4) & 0x01);
	gpio_set_value(GPIO_DATA5, (byte >> 5) & 0x01);
	gpio_set_value(GPIO_DATA6, (byte >> 6) & 0x01);
	gpio_set_value(GPIO_DATA7, (byte >> 7) & 0x01);

	/* clock */
	gpio_set_value(GPIO_DCLK, 1);
	udelay(1);
	gpio_set_value(GPIO_DCLK, 0);
	udelay(1);

	return 0;
}

int fpga_wr_fn(const void *buf, size_t len, int flush, int cookie)
{
	unsigned char *data = (unsigned char *) buf;
	int i;
	int headerlen = len - cyclone2.size;

	if (headerlen < 0)
		return FPGA_FAIL;
	else if (headerlen == sizeof(uint32_t)) {
		const unsigned int fpgavers_len = 11; /* '0x' + 8 hex digits + \0 */
		char fpgavers_str[fpgavers_len];
		snprintf(fpgavers_str, fpgavers_len, "0x%08x",
				be32_to_cpup((uint32_t*)data));
		setenv("fpgavers", fpgavers_str);
	}

	fpga_debug("fpga_wr: buf %p / size %d\n", buf, len);
	for (i = headerlen; i < len; i++)
		_write_fpga(data[i]);
	fpga_debug("-%s\n", __func__);

	return FPGA_SUCCESS;
}