aboutsummaryrefslogtreecommitdiffstats
path: root/firmware/microblaze/lib/xilinx_s3_icap.c
blob: 8aa7fd297d5d74e851fed704dfd7b696e641fef3 (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
/* -*- c -*- */
/*
 * Copyright 2009 Ettus Research LLC
 *
 * 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 3 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/>.
 */


/* Changes required to work for the Spartan-3A series:
 * The ICAP interface on the 3A is 8 bits wide, instead of 32.
 * Everything is Xilinx standard LSB-first.
 * The operations are all different.
 * Commands are 16 bits long, presented to the ICAP interface 8 bits at a time.
*/

#include <xilinx_s3_icap.h>
#include <memory_map.h>
#include <spi_flash_private.h> //for READ_CMD


/* bit swap end-for-end */
static unsigned char
swap8(unsigned char x)
{
  unsigned char r = 0;
  r |= (x >> 7) & 0x01;
  r |= (x >> 5) & 0x02;
  r |= (x >> 3) & 0x04;
  r |= (x >> 1) & 0x08;

  r |= (x << 1) & 0x10;
  r |= (x << 3) & 0x20;
  r |= (x << 5) & 0x40;
  r |= (x << 7) & 0x80;

  return r;
}

void
wr_icap(uint8_t x)
{
	uint8_t t = swap8(x);

	icap_regs->icap = t; //DEBUG: does not swap bits
}

uint8_t
rd_icap(void)
{
	return swap8(icap_regs->icap);
}


void
icap_reload_fpga(uint32_t flash_address)
//this DOES NOT WORK right now. reboot is not getting executed correctly.
{
	union {
		uint32_t i;
		uint8_t c[4];
	} t;
	t.i = flash_address;

	//note! t.c[0] MUST contain the byte-wide read command for the flash device used.
	//for the 25P64, and most other flash devices, this is 0x03.
	t.c[0] = READ_CMD; //legacy command, use FAST_READ_CMD 0x0B after testing

	//TODO: look up the watchdog timer, ensure it won't fire too soon

  //UG332 p279
//	wr_icap(0xff);
//	wr_icap(0xff); //dummy word, probably unnecessary
	wr_icap(0xAA);
	wr_icap(0x99); //sync word
	wr_icap(0x32);
	wr_icap(0x61); //Type 1 write General 1 (1 word)
	wr_icap(t.c[2]); //bits 15-8
	wr_icap(t.c[3]); //bits 7-0
	wr_icap(0x32);
	wr_icap(0x81); //Type 1 write General 2 (1 word)
	wr_icap(t.c[0]); //C0-C8, the byte-wide read command
	wr_icap(t.c[1]); //Upper 8 bits of 24-bit address
	wr_icap(0x30);
	wr_icap(0xA1); //Type 1 write CMD (1 word)
	wr_icap(0x00);
	wr_icap(0x0E); //REBOOT command
	wr_icap(0x20);
	wr_icap(0x00); //Type 1 NOP

}