summaryrefslogtreecommitdiff
path: root/board/prodrive/alpr/fpga.c
blob: 1cce798ee6264764c8c40363c189a961357fb457 (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
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/*
 * (C) Copyright 2006
 * Heiko Schocher, DENX Software Engineering, hs@denx.de
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 *
 */

/*
 * Altera FPGA configuration support for the ALPR computer from prodrive
 */

#include <common.h>
#include <altera.h>
#include <ACEX1K.h>
#include <command.h>
#include <asm/processor.h>
#include <asm/ppc440.h>
#include "fpga.h"

DECLARE_GLOBAL_DATA_PTR;

#if defined(CONFIG_FPGA)

#ifdef FPGA_DEBUG
#define	PRINTF(fmt, args...)	printf(fmt , ##args)
#else
#define	PRINTF(fmt, args...)
#endif

static unsigned long regval;

#define SET_GPIO_REG_0(reg, bit) do {				\
		regval = in32(reg);				\
		regval &= ~(0x80000000 >> bit);			\
		out32(reg, regval);				\
	} while (0)

#define SET_GPIO_REG_1(reg, bit) do {				\
		regval = in32(reg);				\
		regval |= (0x80000000 >> bit);			\
		out32(reg, regval);				\
	} while (0)

#define	SET_GPIO_0(bit)		SET_GPIO_REG_0(GPIO0_OR, bit)
#define	SET_GPIO_1(bit)		SET_GPIO_REG_1(GPIO0_OR, bit)

#define FPGA_PRG		(0x80000000 >> CONFIG_SYS_GPIO_PROG_EN)
#define FPGA_CONFIG		(0x80000000 >> CONFIG_SYS_GPIO_CONFIG)
#define FPGA_DATA		(0x80000000 >> CONFIG_SYS_GPIO_DATA)
#define FPGA_CLK		(0x80000000 >> CONFIG_SYS_GPIO_CLK)
#define OLD_VAL			(FPGA_PRG | FPGA_CONFIG)

#define SET_FPGA(data)		out32(GPIO0_OR, data)

#define FPGA_WRITE_1 do {							    \
	SET_FPGA(OLD_VAL | 0	    | FPGA_DATA);	/* set data to 1 */ \
	SET_FPGA(OLD_VAL | FPGA_CLK | FPGA_DATA);	/* set data to 1 */ \
} while (0)

#define FPGA_WRITE_0 do {							    \
	SET_FPGA(OLD_VAL | 0	    | 0);		/* set data to 0 */ \
	SET_FPGA(OLD_VAL | FPGA_CLK | 0);		/* set data to 1 */ \
} while (0)

/* Plattforminitializations */
/* Here we have to set the FPGA Chain */
/* PROGRAM_PROG_EN	= HIGH */
/* PROGRAM_SEL_DPR	= LOW */
int fpga_pre_fn(int cookie)
{
	/* Enable the FPGA Chain */
	SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_PROG_EN);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_PROG_EN);
	SET_GPIO_1(CONFIG_SYS_GPIO_PROG_EN);
	SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_SEL_DPR);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_SEL_DPR);
	SET_GPIO_0((CONFIG_SYS_GPIO_SEL_DPR));

	/* initialize the GPIO Pins */
	/* output */
	SET_GPIO_0(CONFIG_SYS_GPIO_CLK);
	SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_CLK);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_CLK);

	/* output */
	SET_GPIO_0(CONFIG_SYS_GPIO_DATA);
	SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_DATA);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_DATA);

	/* First we set STATUS to 0 then as an input */
	SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_STATUS);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_STATUS);
	SET_GPIO_0(CONFIG_SYS_GPIO_STATUS);
	SET_GPIO_REG_0(GPIO0_TCR, CONFIG_SYS_GPIO_STATUS);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_STATUS);

	/* output */
	SET_GPIO_REG_1(GPIO0_TCR, CONFIG_SYS_GPIO_CONFIG);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_CONFIG);
	SET_GPIO_0(CONFIG_SYS_GPIO_CONFIG);

	/* input */
	SET_GPIO_0(CONFIG_SYS_GPIO_CON_DON);
	SET_GPIO_REG_0(GPIO0_TCR, CONFIG_SYS_GPIO_CON_DON);
	SET_GPIO_REG_0(GPIO0_ODR, CONFIG_SYS_GPIO_CON_DON);

	/* CONFIG = 0 STATUS = 0 -> FPGA in reset state */
	SET_GPIO_0(CONFIG_SYS_GPIO_CONFIG);
	return FPGA_SUCCESS;
}

/* Set the state of CONFIG Pin */
int fpga_config_fn(int assert_config, int flush, int cookie)
{
	if (assert_config)
		SET_GPIO_1(CONFIG_SYS_GPIO_CONFIG);
	else
		SET_GPIO_0(CONFIG_SYS_GPIO_CONFIG);

	return FPGA_SUCCESS;
}

/* Returns the state of STATUS Pin */
int fpga_status_fn(int cookie)
{
	unsigned long	reg;

	reg = in32(GPIO0_IR);
	if (reg & (0x80000000 >> CONFIG_SYS_GPIO_STATUS)) {
		PRINTF("STATUS = HIGH\n");
		return FPGA_FAIL;
	}
	PRINTF("STATUS = LOW\n");
	return FPGA_SUCCESS;
}

/* Returns the state of CONF_DONE Pin */
int fpga_done_fn(int cookie)
{
	unsigned long	reg;
	reg = in32(GPIO0_IR);
	if (reg & (0x80000000 >> CONFIG_SYS_GPIO_CON_DON)) {
		PRINTF("CONF_DON = HIGH\n");
		return FPGA_FAIL;
	}
	PRINTF("CONF_DON = LOW\n");
	return FPGA_SUCCESS;
}

/* writes the complete buffer to the FPGA
   writing the complete buffer in one function is much faster,
   then calling it for every bit */
int fpga_write_fn(const void *buf, size_t len, int flush, int cookie)
{
	size_t bytecount = 0;
	unsigned char *data = (unsigned char *) buf;
	unsigned char val = 0;
	int		i;
	int len_40 = len / 40;

	while (bytecount < len) {
		val = data[bytecount++];
		i = 8;
		do {
			if (val & 0x01)
				FPGA_WRITE_1;
			else
				FPGA_WRITE_0;

			val >>= 1;
			i--;
		} while (i > 0);

#ifdef CONFIG_SYS_FPGA_PROG_FEEDBACK
		if (bytecount % len_40 == 0) {
			putc('.');		/* let them know we are alive */
#ifdef CONFIG_SYS_FPGA_CHECK_CTRLC
			if (ctrlc())
				return FPGA_FAIL;
#endif
		}
#endif
	}
	return FPGA_SUCCESS;
}

/* called, when programming is aborted */
int fpga_abort_fn(int cookie)
{
	SET_GPIO_1((CONFIG_SYS_GPIO_SEL_DPR));
	return FPGA_SUCCESS;
}

/* called, when programming was succesful */
int fpga_post_fn(int cookie)
{
	return fpga_abort_fn(cookie);
}

/* Note that these are pointers to code that is in Flash.  They will be
 * relocated at runtime.
 */
Altera_CYC2_Passive_Serial_fns fpga_fns = {
	fpga_pre_fn,
	fpga_config_fn,
	fpga_status_fn,
	fpga_done_fn,
	fpga_write_fn,
	fpga_abort_fn,
	fpga_post_fn
};

Altera_desc fpga[CONFIG_FPGA_COUNT] = {
	{Altera_CYC2,
	 passive_serial,
	 Altera_EP2C35_SIZE,
	 (void *) &fpga_fns,
	 NULL,
	 0}
};

/*
 * Initialize the fpga.  Return 1 on success, 0 on failure.
 */
int alpr_fpga_init(void)
{
	int i;

	PRINTF("%s:%d: Initialize FPGA interface\n", __func__, __LINE__);
	fpga_init();

	for (i = 0; i < CONFIG_FPGA_COUNT; i++) {
		PRINTF("%s:%d: Adding fpga %d\n", __func__, __LINE__, i);
		fpga_add(fpga_altera, &fpga[i]);
	}
	return 1;
}

#endif