summaryrefslogtreecommitdiff
path: root/arch/sh/boards/overdrive/fpga.c
blob: 3a1ec9403441eb41b871d8ba8a0c8d322b913016 (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
/* 
 * Copyright (C) 2000 David J. Mckay (david.mckay@st.com)
 *
 * May be copied or modified under the terms of the GNU General Public
 * License.  See linux/COPYING for more information.                            
 *
 * This file handles programming up the Altera Flex10K that interfaces to
 * the Galileo, and does the PS/2 keyboard and mouse
 *
 */


#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
#include <linux/delay.h>


#include <asm/overdriver/gt64111.h>
#include <asm/overdrive/overdrive.h>
#include <asm/overdrive/fpga.h>

#define FPGA_NotConfigHigh()  (*FPGA_ControlReg) = (*FPGA_ControlReg) | ENABLE_FPGA_BIT
#define FPGA_NotConfigLow()   (*FPGA_ControlReg) = (*FPGA_ControlReg) & RESET_FPGA_MASK

/* I need to find out what (if any) the real delay factor here is */
/* The delay is definately not critical */
#define long_delay() {int i;for(i=0;i<10000;i++);}
#define short_delay() {int i;for(i=0;i<100;i++);}

static void __init program_overdrive_fpga(const unsigned char *fpgacode,
					  int size)
{
	int timeout = 0;
	int i, j;
	unsigned char b;
	static volatile unsigned char *FPGA_ControlReg =
	    (volatile unsigned char *) (OVERDRIVE_CTRL);
	static volatile unsigned char *FPGA_ProgramReg =
	    (volatile unsigned char *) (FPGA_DCLK_ADDRESS);

	printk("FPGA:  Commencing FPGA Programming\n");

	/* The PCI reset but MUST be low when programming the FPGA !!! */
	b = (*FPGA_ControlReg) & RESET_PCI_MASK;

	(*FPGA_ControlReg) = b;

	/* Prepare FPGA to program */

	FPGA_NotConfigHigh();
	long_delay();

	FPGA_NotConfigLow();
	short_delay();

	while ((*FPGA_ProgramReg & FPGA_NOT_STATUS) != 0) {
		printk("FPGA:  Waiting for NotStatus to go Low ... \n");
	}

	FPGA_NotConfigHigh();

	/* Wait for FPGA "ready to be programmed" signal */
	printk("FPGA:  Waiting for NotStatus to go high (FPGA ready)... \n");

	for (timeout = 0;
	     (((*FPGA_ProgramReg & FPGA_NOT_STATUS) == 0)
	      && (timeout < FPGA_TIMEOUT)); timeout++);

	/* Check if timeout condition occured - i.e. an error */

	if (timeout == FPGA_TIMEOUT) {
		printk
		    ("FPGA:  Failed to program - Timeout waiting for notSTATUS to go high\n");
		return;
	}

	printk("FPGA:  Copying data to FPGA ... %d bytes\n", size);

	/* Copy array to FPGA - bit at a time */

	for (i = 0; i < size; i++) {
		volatile unsigned w = 0;

		for (j = 0; j < 8; j++) {
			*FPGA_ProgramReg = (fpgacode[i] >> j) & 0x01;
			short_delay();
		}
		if ((i & 0x3ff) == 0) {
			printk(".");
		}
	}

	/* Waiting for CONFDONE to go high - means the program is complete  */

	for (timeout = 0;
	     (((*FPGA_ProgramReg & FPGA_CONFDONE) == 0)
	      && (timeout < FPGA_TIMEOUT)); timeout++) {

		*FPGA_ProgramReg = 0x0;
		long_delay();
	}

	if (timeout == FPGA_TIMEOUT) {
		printk
		    ("FPGA:  Failed to program - Timeout waiting for CONFDONE to go high\n");
		return;
	} else {		/* Clock another 10 times - gets the device into a working state      */
		for (i = 0; i < 10; i++) {
			*FPGA_ProgramReg = 0x0;
			short_delay();
		}
	}

	printk("FPGA:  Programming complete\n");
}


static const unsigned char __init fpgacode[] = {
#include "./overdrive.ttf"	/* Code from maxplus2 compiler */
	, 0, 0
};


int __init init_overdrive_fpga(void)
{
	program_overdrive_fpga(fpgacode, sizeof(fpgacode));

	return 0;
}