]> CyberLeo.Net >> Repos - FreeBSD/releng/8.2.git/blob - sys/contrib/octeon-sdk/cvmx-twsi.c
Copy stable/8 to releng/8.2 in preparation for FreeBSD-8.2 release.
[FreeBSD/releng/8.2.git] / sys / contrib / octeon-sdk / cvmx-twsi.c
1 /***********************license start***************
2  *  Copyright (c) 2003-2008 Cavium Networks (support@cavium.com). All rights
3  *  reserved.
4  *
5  *
6  *  Redistribution and use in source and binary forms, with or without
7  *  modification, are permitted provided that the following conditions are
8  *  met:
9  *
10  *      * Redistributions of source code must retain the above copyright
11  *        notice, this list of conditions and the following disclaimer.
12  *
13  *      * Redistributions in binary form must reproduce the above
14  *        copyright notice, this list of conditions and the following
15  *        disclaimer in the documentation and/or other materials provided
16  *        with the distribution.
17  *
18  *      * Neither the name of Cavium Networks nor the names of
19  *        its contributors may be used to endorse or promote products
20  *        derived from this software without specific prior written
21  *        permission.
22  *
23  *  TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
24  *  AND WITH ALL FAULTS AND CAVIUM NETWORKS MAKES NO PROMISES, REPRESENTATIONS
25  *  OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH
26  *  RESPECT TO THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY
27  *  REPRESENTATION OR DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT
28  *  DEFECTS, AND CAVIUM SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES
29  *  OF TITLE, MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR
30  *  PURPOSE, LACK OF VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET
31  *  POSSESSION OR CORRESPONDENCE TO DESCRIPTION.  THE ENTIRE RISK ARISING OUT
32  *  OF USE OR PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
33  *
34  *
35  *  For any questions regarding licensing please contact marketing@caviumnetworks.com
36  *
37  ***********************license end**************************************/
38
39
40
41
42
43
44 /**
45  * @file
46  *
47  * Interface to the TWSI / I2C bus
48  *
49  * <hr>$Revision: 41586 $<hr>
50  *
51  */
52
53 #include "cvmx.h"
54 #include "cvmx-twsi.h"
55
56
57
58
59
60 /**
61  * Do a twsi read from a 7 bit device address using an (optional) internal address.
62  * Up to 8 bytes can be read at a time.
63  * 
64  * @param twsi_id   which Octeon TWSI bus to use
65  * @param dev_addr  Device address (7 bit)
66  * @param internal_addr
67  *                  Internal address.  Can be 0, 1 or 2 bytes in width
68  * @param num_bytes Number of data bytes to read
69  * @param ia_width_bytes
70  *                  Internal address size in bytes (0, 1, or 2)
71  * @param data      Pointer argument where the read data is returned.
72  * 
73  * @return read data returned in 'data' argument
74  *         Number of bytes read on success
75  *         -1 on failure
76  */
77 int cvmx_twsix_read_ia(int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t *data)
78 {
79     cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
80     cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
81
82     if (num_bytes < 1 || num_bytes > 8 || !data || ia_width_bytes < 0 || ia_width_bytes > 2)
83         return -1;
84
85     twsi_ext.u64 = 0;
86     sw_twsi_val.u64 = 0;
87     sw_twsi_val.s.v = 1;
88     sw_twsi_val.s.r = 1;
89     sw_twsi_val.s.sovr = 1;
90     sw_twsi_val.s.size = num_bytes - 1;
91     sw_twsi_val.s.a = dev_addr;
92
93     if (ia_width_bytes > 0)
94     {
95         sw_twsi_val.s.op = 1;
96         sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f;
97         sw_twsi_val.s.eop_ia = internal_addr & 0x7;
98     } 
99     if (ia_width_bytes == 2)
100     {
101         sw_twsi_val.s.eia = 1;
102         twsi_ext.s.ia = internal_addr >> 8;
103         cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
104     }
105
106     cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
107     while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
108         ;
109     if (!sw_twsi_val.s.r)
110         return -1;
111
112     *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8)));
113     if (num_bytes > 4)
114     {
115         twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id));
116         *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32);
117
118     }
119     return num_bytes;
120 }
121
122
123
124
125 /**
126  * Read from a TWSI device (7 bit device address only) without generating any
127  * internal addresses.
128  * Read from 1-8 bytes and returns them in the data pointer.
129  * 
130  * @param twsi_id   TWSI interface on Octeon to use
131  * @param dev_addr  TWSI device address (7 bit only)
132  * @param num_bytes number of bytes to read
133  * @param data      Pointer to data read from TWSI device
134  * 
135  * @return Number of bytes read on success
136  *         -1 on error
137  */
138 int cvmx_twsix_read(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t *data)
139 {
140     cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
141     cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
142
143     if (num_bytes > 8 || num_bytes < 1)
144         return -1;
145
146     sw_twsi_val.u64 = 0;
147     sw_twsi_val.s.v = 1;
148     sw_twsi_val.s.r = 1;
149     sw_twsi_val.s.a = dev_addr;
150     sw_twsi_val.s.sovr = 1;
151     sw_twsi_val.s.size = num_bytes - 1;
152
153     cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
154     while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
155         ;
156     if (!sw_twsi_val.s.r)
157         return -1;
158
159     *data = (sw_twsi_val.s.d & (0xFFFFFFFF >> (32 - num_bytes*8)));
160     if (num_bytes > 4)
161     {
162         twsi_ext.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id));
163         *data |= ((unsigned long long)(twsi_ext.s.d & (0xFFFFFFFF >> (32 - num_bytes*8))) << 32);
164
165     }
166     return num_bytes;
167 }
168
169
170 /**
171  * Perform a twsi write operation to a 7 bit device address.
172  * 
173  * Note that many eeprom devices have page restrictions regarding address boundaries
174  * that can be crossed in one write operation.  This is device dependent, and this routine
175  * does nothing in this regard.
176  * This command does not generate any internal addressess.
177  * 
178  * @param twsi_id   Octeon TWSI interface to use
179  * @param dev_addr  TWSI device address
180  * @param num_bytes Number of bytes to write (between 1 and 8 inclusive)
181  * @param data      Data to write
182  * 
183  * @return 0 on success
184  *         -1 on failure
185  */
186 int cvmx_twsix_write(int twsi_id, uint8_t dev_addr, int num_bytes, uint64_t data)
187 {
188     cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
189
190     if (num_bytes > 8 || num_bytes < 1)
191         return -1;
192
193     sw_twsi_val.u64 = 0;
194     sw_twsi_val.s.v = 1;
195     sw_twsi_val.s.a = dev_addr;
196     sw_twsi_val.s.d = data & 0xffffffff;
197     sw_twsi_val.s.sovr = 1;
198     sw_twsi_val.s.size = num_bytes - 1;
199     if (num_bytes > 4)
200     {
201         /* Upper four bytes go into a separate register */
202         cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
203         twsi_ext.u64 = 0;
204         twsi_ext.s.d = data >> 32;
205         cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
206     }
207     cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
208     while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
209         ;
210     if (!sw_twsi_val.s.r)
211         return -1;
212
213     return 0;
214 }
215
216 /**
217  * Write 1-8 bytes to a TWSI device using an internal address.
218  * 
219  * @param twsi_id   which TWSI interface on Octeon to use
220  * @param dev_addr  TWSI device address (7 bit only)
221  * @param internal_addr
222  *                  TWSI internal address (0, 8, or 16 bits)
223  * @param num_bytes Number of bytes to write (1-8)
224  * @param ia_width_bytes
225  *                  internal address width, in bytes (0, 1, 2)
226  * @param data      Data to write.  Data is written MSB first on the twsi bus, and only the lower
227  *                  num_bytes bytes of the argument are valid.  (If a 2 byte write is done, only
228  *                  the low 2 bytes of the argument is used.
229  * 
230  * @return Number of bytes read on success,
231  *         -1 on error
232  */
233 int cvmx_twsix_write_ia(int twsi_id, uint8_t dev_addr, uint16_t internal_addr, int num_bytes, int ia_width_bytes, uint64_t data)
234 {
235     cvmx_mio_twsx_sw_twsi_t sw_twsi_val;
236     cvmx_mio_twsx_sw_twsi_ext_t twsi_ext;
237     int to;
238
239     if (num_bytes < 1 || num_bytes > 8 || ia_width_bytes < 0 || ia_width_bytes > 2)
240         return -1;
241
242     twsi_ext.u64 = 0;
243
244     sw_twsi_val.u64 = 0;
245     sw_twsi_val.s.v = 1;
246     sw_twsi_val.s.sovr = 1;
247     sw_twsi_val.s.size = num_bytes - 1;
248     sw_twsi_val.s.a = dev_addr;
249     sw_twsi_val.s.d = 0xFFFFFFFF & data;
250
251     if (ia_width_bytes > 0)
252     {
253         sw_twsi_val.s.op = 1;
254         sw_twsi_val.s.ia = (internal_addr >> 3) & 0x1f;
255         sw_twsi_val.s.eop_ia = internal_addr & 0x7;
256     } 
257     if (ia_width_bytes == 2)
258     {
259         sw_twsi_val.s.eia = 1;
260         twsi_ext.s.ia = internal_addr >> 8;
261         cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
262     }
263     if (num_bytes > 4)
264         twsi_ext.s.d = data >> 32;
265
266
267     cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI_EXT(twsi_id), twsi_ext.u64);
268     cvmx_write_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id), sw_twsi_val.u64);
269     while (((cvmx_mio_twsx_sw_twsi_t)(sw_twsi_val.u64 = cvmx_read_csr(CVMX_MIO_TWSX_SW_TWSI(twsi_id)))).s.v)
270         ;
271
272     /* Poll until reads succeed, or polling times out */
273     to = 100;
274     while (to-- > 0)
275     {
276         uint64_t data;
277         if (cvmx_twsix_read(twsi_id, dev_addr, 1, &data) >= 0)
278             break;
279     }
280     if (to <= 0)
281         return -1;
282
283     return num_bytes;
284 }
285