summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-socfpga/cyclone5-scan-manager.c
blob: cf076c3885b304cc6125d3b456a49d3b080d8e87 (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
/*
 *  Copyright (C) 2012 Altera Corporation <www.altera.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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <common.h>
#include <io.h>
#include <mach/cyclone5-freeze-controller.h>
#include <mach/cyclone5-scan-manager.h>

/*
 * @fn scan_mgr_io_scan_chain_engine_is_idle
 *
 * @brief function to check IO scan chain engine status and wait if the
 *        engine is active. Poll the IO scan chain engine till maximum iteration
 *        reached.
 *
 * @param max_iter uint32_t [in] - maximum polling loop to revent infinite loop
 */
static int scan_mgr_io_scan_chain_engine_is_idle(uint32_t max_iter)
{
	uint32_t scanmgr_status;

	scanmgr_status = readl(SCANMGR_STAT_ADDRESS +
		CYCLONE5_SCANMGR_ADDRESS);

	/* Poll the engine until the scan engine is inactive */
	while (SCANMGR_STAT_ACTIVE_GET(scanmgr_status)
		|| (SCANMGR_STAT_WFIFOCNT_GET(scanmgr_status) > 0)) {

		max_iter--;

		if (max_iter > 0) {
			scanmgr_status = readl(
				CYCLONE5_SCANMGR_ADDRESS +
				SCANMGR_STAT_ADDRESS);
		} else {
			return 0;
		}
	}
	return 1;
}

/*
 * scan_mgr_io_scan_chain_prg
 * Program HPS IO Scan Chain
 */
int scan_mgr_io_scan_chain_prg(enum io_scan_chain io_scan_chain_id,
		uint32_t io_scan_chain_len_in_bits,
		const unsigned long *iocsr_scan_chain)
{
	uint16_t tdi_tdo_header;
	uint32_t io_program_iter;
	uint32_t io_scan_chain_data_residual;
	uint32_t residual;
	uint32_t i;
	uint32_t index = 0;
	uint32_t val;
	int ret;
	void __iomem *sysmgr = (void *)CYCLONE5_SYSMGR_ADDRESS;
	void __iomem *scanmgr = (void *)CYCLONE5_SCANMGR_ADDRESS;

	/* De-assert reinit if the IO scan chain is intended for HIO */
	if (io_scan_chain_id == IO_SCAN_CHAIN_3) {
		val = readl(sysmgr + SYSMGR_FRZCTRL_HIOCTRL_ADDRESS);
		val &= ~SYSMGR_FRZCTRL_HIOCTRL_DLLRST_MASK;
		writel(val, sysmgr + SYSMGR_FRZCTRL_HIOCTRL_ADDRESS);
	} /* if (HIO) */

	/*
	 * Check if the scan chain engine is inactive and the
	 * WFIFO is empty before enabling the IO scan chain
	 */
	if (!scan_mgr_io_scan_chain_engine_is_idle(MAX_WAITING_DELAY_IO_SCAN_ENGINE))
		return -EBUSY;

	/*
	 * Enable IO Scan chain based on scan chain id
	 * Note: only one chain can be enabled at a time
	 */
	val = readl(scanmgr + SCANMGR_EN_ADDRESS);
	val |= 1 << io_scan_chain_id;
	writel(val, scanmgr + SCANMGR_EN_ADDRESS);

	/*
	 * Calculate number of iteration needed for
	 * full 128-bit (4 x32-bits) bits shifting.
	 * Each TDI_TDO packet can shift in maximum 128-bits
	 */
	io_program_iter = io_scan_chain_len_in_bits >> IO_SCAN_CHAIN_128BIT_SHIFT;
	io_scan_chain_data_residual = io_scan_chain_len_in_bits & IO_SCAN_CHAIN_128BIT_MASK;

	/*
	 * Construct TDI_TDO packet for
	 * 128-bit IO scan chain (2 bytes)
	 */
	tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE |
		(TDI_TDO_MAX_PAYLOAD << TDI_TDO_HEADER_SECOND_BYTE_SHIFT);

	/* Program IO scan chain in 128-bit iteration */
	for (i = 0; i < io_program_iter; i++) {

		/* write TDI_TDO packet header to scan manager */
		writel(tdi_tdo_header, (scanmgr + SCANMGR_FIFODOUBLEBYTE_ADDRESS));

		/* calculate array index */
		index = i * 4;

		/*
		 * write 4 successive 32-bit IO scan
		 * chain data into WFIFO
		 */
		writel(iocsr_scan_chain[index], (scanmgr + SCANMGR_FIFOQUADBYTE_ADDRESS));
		writel(iocsr_scan_chain[index + 1], (scanmgr + SCANMGR_FIFOQUADBYTE_ADDRESS));
		writel(iocsr_scan_chain[index + 2], (scanmgr + SCANMGR_FIFOQUADBYTE_ADDRESS));
		writel(iocsr_scan_chain[index + 3], (scanmgr + SCANMGR_FIFOQUADBYTE_ADDRESS));

		/*
		 * Check if the scan chain engine has completed the
		 * IO scan chain data shifting
		 */
		if (!scan_mgr_io_scan_chain_engine_is_idle(MAX_WAITING_DELAY_IO_SCAN_ENGINE)) {
			ret = -EBUSY;
			goto out_disable;
		}
	}

	/* Calculate array index for final TDI_TDO packet */
	index = io_program_iter * 4;

	/* Final TDI_TDO packet if any */
	if (0 != io_scan_chain_data_residual) {
		/*
		 * Calculate number of quad bytes FIFO write
		 * needed for the final TDI_TDO packet
		 */
		io_program_iter = io_scan_chain_data_residual >> IO_SCAN_CHAIN_32BIT_SHIFT;

		/*
		 * Construct TDI_TDO packet for remaining IO
		 * scan chain (2 bytes)
		 */
		tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE |
			((io_scan_chain_data_residual - 1) << TDI_TDO_HEADER_SECOND_BYTE_SHIFT);

		/*
		 * Program the last part of IO scan chain
		 * write TDI_TDO packet header (2 bytes) to
		 * scan manager
		 */
		writel(tdi_tdo_header, (scanmgr + SCANMGR_FIFODOUBLEBYTE_ADDRESS));

		for (i = 0; i < io_program_iter; i++) {

			/*
			 * write remaining scan chain data into scan
			 * manager WFIFO with 4 bytes write
			*/
			writel(iocsr_scan_chain[index + i],
					(scanmgr + SCANMGR_FIFOQUADBYTE_ADDRESS));
		}

		index += io_program_iter;
		residual = io_scan_chain_data_residual & IO_SCAN_CHAIN_32BIT_MASK;

		if (IO_SCAN_CHAIN_PAYLOAD_24BIT < residual) {
			/*
			 * write the last 4B scan chain data
			 * into scan manager WFIFO
			 */
			writel(iocsr_scan_chain[index],
					(scanmgr + SCANMGR_FIFOQUADBYTE_ADDRESS));
		} else {
			/*
			 * write the remaining 1 - 3 bytes scan chain
			 * data into scan manager WFIFO byte by byte
			 * to prevent JTAG engine shifting unused data
			 * from the FIFO and mistaken the data as a
			 * valid command (even though unused bits are
			 * set to 0, but just to prevent hardware
			 * glitch)
			 */
			for (i = 0; i < residual; i += 8) {
				writel(((iocsr_scan_chain[index] >> i) & IO_SCAN_CHAIN_BYTE_MASK),
						(scanmgr + SCANMGR_FIFOSINGLEBYTE_ADDRESS));
			}
		}

		/*
		 * Check if the scan chain engine has completed the
		 * IO scan chain data shifting
		 */
		if (!scan_mgr_io_scan_chain_engine_is_idle(MAX_WAITING_DELAY_IO_SCAN_ENGINE)) {
			ret = -EBUSY;
			goto out_disable;
		}
	} /* if (io_scan_chain_data_residual) */

	ret = 0;

out_disable:
	/* Disable IO Scan chain when configuration done*/
	val = readl(scanmgr + SCANMGR_EN_ADDRESS);
	val &= ~(1 << io_scan_chain_id);
	writel(val, scanmgr + SCANMGR_EN_ADDRESS);

	return ret;
}