xref: /titanic_51/usr/src/boot/sys/boot/arm/at91/bootspi/ee.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
1 /******************************************************************************
2  *
3  * Filename: eeprom.c
4  *
5  * Instantiation of eeprom routines
6  *
7  * Revision information:
8  *
9  * 28AUG2004	kb_admin	initial creation - adapted from Atmel sources
10  * 12JAN2005	kb_admin	fixed clock generation, write polling, init
11  *
12  * BEGIN_KBDD_BLOCK
13  * No warranty, expressed or implied, is included with this software.  It is
14  * provided "AS IS" and no warranty of any kind including statutory or aspects
15  * relating to merchantability or fitness for any purpose is provided.  All
16  * intellectual property rights of others is maintained with the respective
17  * owners.  This software is not copyrighted and is intended for reference
18  * only.
19  * END_BLOCK
20  *
21  * $FreeBSD$
22  *****************************************************************************/
23 
24 #include "at91rm9200_lowlevel.h"
25 #include "at91rm9200.h"
26 #include "lib.h"
27 #include "ee.h"
28 
29 /******************************* GLOBALS *************************************/
30 
31 
32 /*********************** PRIVATE FUNCTIONS/DATA ******************************/
33 
34 
35 /* Use a macro to calculate the TWI clock generator value to save code space. */
36 #define AT91C_TWSI_CLOCK	100000
37 #define TWSI_EEPROM_ADDRESS	0x40
38 
39 #define TWI_CLK_BASE_DIV	((AT91C_MASTER_CLOCK/(4*AT91C_TWSI_CLOCK)) - 2)
40 #define SET_TWI_CLOCK	((0x00010000) | (TWI_CLK_BASE_DIV) | (TWI_CLK_BASE_DIV << 8))
41 
42 
43 /*************************** GLOBAL FUNCTIONS ********************************/
44 
45 
46 /*
47  * .KB_C_FN_DEFINITION_START
48  * void InitEEPROM(void)
49  *  This global function initializes the EEPROM interface (TWI).  Intended
50  * to be called a single time.
51  * .KB_C_FN_DEFINITION_END
52  */
53 void
54 EEInit(void)
55 {
56 
57 	AT91PS_TWI twiPtr = (AT91PS_TWI)AT91C_BASE_TWI;
58 
59 	AT91PS_PIO pPio = (AT91PS_PIO)AT91C_BASE_PIOA;
60 	AT91PS_PMC pPMC = (AT91PS_PMC)AT91C_BASE_PMC;
61 
62 	pPio->PIO_ASR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
63 	pPio->PIO_PDR = AT91C_PIO_PA25 | AT91C_PIO_PA26;
64 
65 	pPio->PIO_MDDR = ~AT91C_PIO_PA25;
66 	pPio->PIO_MDER = AT91C_PIO_PA25;
67 
68 	pPMC->PMC_PCER = 1u << AT91C_ID_TWI;
69 
70 	twiPtr->TWI_IDR = 0xffffffffu;
71 	twiPtr->TWI_CR = AT91C_TWI_SWRST;
72 	twiPtr->TWI_CR = AT91C_TWI_MSEN | AT91C_TWI_SVDIS;
73 
74 	twiPtr->TWI_CWGR = SET_TWI_CLOCK;
75 }
76 
77 static inline unsigned
78 iicaddr(unsigned ee_off)
79 {
80     return (TWSI_EEPROM_ADDRESS | ((ee_off >> 8) & 0x7));
81 }
82 
83 
84 /*
85  * .KB_C_FN_DEFINITION_START
86  * void ReadEEPROM(unsigned ee_addr, char *data_addr, unsigned size)
87  *  This global function reads data from the eeprom at ee_addr storing data
88  * to data_addr for size bytes.  Assume the TWI has been initialized.
89  * This function does not utilize the page read mode to simplify the code.
90  * .KB_C_FN_DEFINITION_END
91  */
92 void
93 EERead(unsigned ee_off, char *data_addr, unsigned size)
94 {
95 	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
96 	unsigned int status;
97 
98 	if ((ee_off & ~0xff) != ((ee_off + size) & ~0xff)) {
99 		printf("Crosses page boundary: 0x%x 0x%x\n", ee_off, size);
100 		return;
101 	}
102 
103 	status = twiPtr->TWI_SR;
104 	status = twiPtr->TWI_RHR;
105 	twiPtr->TWI_MMR = (iicaddr(ee_off) << 16) | AT91C_TWI_IADRSZ_1_BYTE |
106 	    AT91C_TWI_MREAD;
107 	twiPtr->TWI_IADR = ee_off & 0xff;
108 	twiPtr->TWI_CR = AT91C_TWI_START;
109 	while (size-- > 1) {
110 		while (!(twiPtr->TWI_SR & AT91C_TWI_RXRDY))
111 			continue;
112 		*(data_addr++) = twiPtr->TWI_RHR;
113 	}
114 	twiPtr->TWI_CR = AT91C_TWI_STOP;
115 	status = twiPtr->TWI_SR;
116 	while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
117 		continue;
118 	*data_addr = twiPtr->TWI_RHR;
119 }
120 
121 
122 /*
123  * .KB_C_FN_DEFINITION_START
124  * void WriteEEPROM(unsigned ee_off, char *data_addr, unsigned size)
125  *  This global function writes data to the eeprom at ee_off using data
126  * from data_addr for size bytes.  Assume the TWI has been initialized.
127  * This function does not utilize the page write mode as the write time is
128  * much greater than the time required to access the device for byte-write
129  * functionality.  This allows the function to be much simpler.
130  * .KB_C_FN_DEFINITION_END
131  */
132 void
133 EEWrite(unsigned ee_off, const char *data_addr, unsigned size)
134 {
135 	const AT91PS_TWI 	twiPtr = AT91C_BASE_TWI;
136 	unsigned		status;
137 	char			test_data;
138 
139 	while (size--) {
140 		// Set the TWI Master Mode Register
141 		twiPtr->TWI_MMR = (iicaddr(ee_off) << 16) |
142 		    AT91C_TWI_IADRSZ_1_BYTE;
143 		twiPtr->TWI_IADR = ee_off++;
144 		status = twiPtr->TWI_SR;
145 
146 		// Load one data byte
147 		twiPtr->TWI_THR = *(data_addr++);
148 		twiPtr->TWI_CR = AT91C_TWI_START;
149 		while (!(twiPtr->TWI_SR & AT91C_TWI_TXRDY))
150 			continue;
151 		twiPtr->TWI_CR = AT91C_TWI_STOP;
152 		status = twiPtr->TWI_SR;
153 		while (!(twiPtr->TWI_SR & AT91C_TWI_TXCOMP))
154 			continue;
155 
156 		// wait for write operation to complete, it is done once
157 		// we can read it back...
158 		EERead(ee_off, &test_data, 1);
159 	}
160 }
161