aboutsummaryrefslogtreecommitdiff
path: root/board/theadorable/fpga.c
blob: 56d3647227bb50bbc11315ddbe256a22356c116d (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
// SPDX-License-Identifier: GPL-2.0+
/*
 * Copyright (C) 2016 Stefan Roese <sr@denx.de>
 */

#include <altera.h>
#include <errno.h>
#include <log.h>
#include <time.h>
#include <asm/gpio.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/soc.h>
#include <asm/arch-mvebu/spi.h>
#include "theadorable.h"

/*
 * FPGA programming support
 */
static int fpga_pre_fn(int cookie)
{
	int gpio_config = COOKIE2CONFIG(cookie);
	int gpio_done = COOKIE2DONE(cookie);
	int ret;

	debug("%s (%d): cookie=%08x gpio_config=%d gpio_done=%d\n",
	      __func__, __LINE__, cookie, gpio_config, gpio_done);

	/* Configure config pin */
	/* Set to output */
	ret = gpio_request(gpio_config, "CONFIG");
	if (ret < 0)
		return ret;
	gpio_direction_output(gpio_config, 1);

	/* Configure done pin */
	/* Set to input */
	ret = gpio_request(gpio_done, "DONE");
	if (ret < 0)
		return ret;

	gpio_direction_input(gpio_done);

	return 0;
}

static int fpga_config_fn(int assert, int flush, int cookie)
{
	int gpio_config = COOKIE2CONFIG(cookie);

	debug("%s (%d): cookie=%08x gpio_config=%d\n",
	      __func__, __LINE__, cookie, gpio_config);

	if (assert)
		gpio_set_value(gpio_config, 1);
	else
		gpio_set_value(gpio_config, 0);

	return 0;
}

static int fpga_write_fn(const void *buf, size_t len, int flush, int cookie)
{
	int spi_bus = COOKIE2SPI_BUS(cookie);
	int spi_dev = COOKIE2SPI_DEV(cookie);
	struct kwspi_registers *reg;
	u32 control_reg;
	u32 config_reg;
	void *dst;

	/*
	 * Write data to FPGA attached to SPI bus via SPI direct write.
	 * This results in the fastest and easiest way to program the
	 * bitstream into the FPGA.
	 */
	debug("%s (%d): cookie=%08x spi_bus=%d spi_dev=%d\n",
	      __func__, __LINE__, cookie, spi_bus, spi_dev);

	if (spi_bus == 0) {
		reg = (struct kwspi_registers *)MVEBU_REGISTER(0x10600);
		dst = (void *)SPI_BUS0_DEV1_BASE;
	} else {
		reg = (struct kwspi_registers *)MVEBU_REGISTER(0x10680);
		dst = (void *)SPI_BUS1_DEV2_BASE;
	}

	/* Configure SPI controller for direct access mode */
	control_reg = readl(&reg->ctrl);
	config_reg = readl(&reg->cfg);
	writel(0x00000214, &reg->cfg);		/* 27MHz clock */
	writel(0x00000000, &reg->dw_cfg);	/* don't de-asset CS */
	writel(KWSPI_CSN_ACT, &reg->ctrl);	/* activate CS */

	/* Copy data to the SPI direct mapped window */
	memcpy(dst, buf, len);

	/* Restore original register values */
	writel(control_reg, &reg->ctrl);
	writel(config_reg, &reg->cfg);

	return 0;
}

/* Returns the state of CONF_DONE Pin */
static int fpga_done_fn(int cookie)
{
	int gpio_done = COOKIE2DONE(cookie);
	unsigned long ts;

	debug("%s (%d): cookie=%08x gpio_done=%d\n",
	      __func__, __LINE__, cookie, gpio_done);

	ts = get_timer(0);
	do {
		if (gpio_get_value(gpio_done))
			return 0;
	} while (get_timer(ts) < 1000);

	/* timeout so return error */
	return -ENODEV;
}

static altera_board_specific_func stratixv_fns = {
	.pre = fpga_pre_fn,
	.config = fpga_config_fn,
	.write = fpga_write_fn,
	.done = fpga_done_fn,
};

static Altera_desc altera_fpga[] = {
	{
		/* Family */
		Altera_StratixV,
		/* Interface type */
		passive_serial,
		/* No limitation as additional data will be ignored */
		-1,
		/* Device function table */
		(void *)&stratixv_fns,
		/* Base interface address specified in driver */
		NULL,
		/* Cookie implementation */
		/*
		 * In this 32bit word the following information is coded:
		 * Bit 31 ... Bit 0
		 * SPI-Bus | SPI-Dev | Config-Pin | Done-Pin
		 */
		FPGA_COOKIE(0, 1, 26, 7)
	},
	{
		/* Family */
		Altera_StratixV,
		/* Interface type */
		passive_serial,
		/* No limitation as additional data will be ignored */
		-1,
		/* Device function table */
		(void *)&stratixv_fns,
		/* Base interface address specified in driver */
		NULL,
		/* Cookie implementation */
		/*
		 * In this 32bit word the following information is coded:
		 * Bit 31 ... Bit 0
		 * SPI-Bus | SPI-Dev | Config-Pin | Done-Pin
		 */
		FPGA_COOKIE(1, 2, 29, 9)
	},
};

/* Add device descriptor to FPGA device table */
void board_fpga_add(void)
{
	int i;

	fpga_init();
	for (i = 0; i < ARRAY_SIZE(altera_fpga); i++)
		fpga_add(fpga_altera, &altera_fpga[i]);
}