1215976Sjmallett/***********************license start***************
2232812Sjmallett * Copyright (c) 2003-2010  Cavium Inc. (support@cavium.com). All rights
3215976Sjmallett * reserved.
4215976Sjmallett *
5215976Sjmallett *
6215976Sjmallett * Redistribution and use in source and binary forms, with or without
7215976Sjmallett * modification, are permitted provided that the following conditions are
8215976Sjmallett * met:
9215976Sjmallett *
10215976Sjmallett *   * Redistributions of source code must retain the above copyright
11215976Sjmallett *     notice, this list of conditions and the following disclaimer.
12215976Sjmallett *
13215976Sjmallett *   * Redistributions in binary form must reproduce the above
14215976Sjmallett *     copyright notice, this list of conditions and the following
15215976Sjmallett *     disclaimer in the documentation and/or other materials provided
16215976Sjmallett *     with the distribution.
17215976Sjmallett
18232812Sjmallett *   * Neither the name of Cavium Inc. nor the names of
19215976Sjmallett *     its contributors may be used to endorse or promote products
20215976Sjmallett *     derived from this software without specific prior written
21215976Sjmallett *     permission.
22215976Sjmallett
23215976Sjmallett * This Software, including technical data, may be subject to U.S. export  control
24215976Sjmallett * laws, including the U.S. Export Administration Act and its  associated
25215976Sjmallett * regulations, and may be subject to export or import  regulations in other
26215976Sjmallett * countries.
27215976Sjmallett
28215976Sjmallett * TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED "AS IS"
29232812Sjmallett * AND WITH ALL FAULTS AND CAVIUM INC. MAKES NO PROMISES, REPRESENTATIONS OR
30215976Sjmallett * WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO
31215976Sjmallett * THE SOFTWARE, INCLUDING ITS CONDITION, ITS CONFORMITY TO ANY REPRESENTATION OR
32215976Sjmallett * DESCRIPTION, OR THE EXISTENCE OF ANY LATENT OR PATENT DEFECTS, AND CAVIUM
33215976Sjmallett * SPECIFICALLY DISCLAIMS ALL IMPLIED (IF ANY) WARRANTIES OF TITLE,
34215976Sjmallett * MERCHANTABILITY, NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF
35215976Sjmallett * VIRUSES, ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
36215976Sjmallett * CORRESPONDENCE TO DESCRIPTION. THE ENTIRE  RISK ARISING OUT OF USE OR
37215976Sjmallett * PERFORMANCE OF THE SOFTWARE LIES WITH YOU.
38215976Sjmallett ***********************license end**************************************/
39215976Sjmallett
40215976Sjmallett
41215976Sjmallett
42215976Sjmallett
43215976Sjmallett
44215976Sjmallett/* This file contains support functions for the Cortina IXF18201 SPI->XAUI dual
45215976Sjmallett** MAC.  The IXF18201 has dual SPI and dual XAUI interfaces to provide 2 10 gigabit
46215976Sjmallett** interfaces.
47215976Sjmallett** This file supports the EBT5810 evaluation board.  To support a different board,
48215976Sjmallett** the 16 bit read/write functions would need to be customized for that board, and the
49215976Sjmallett** IXF18201 may need to be initialized differently as well.
50215976Sjmallett**
51215976Sjmallett** The IXF18201 and Octeon are configured for 2 SPI channels per interface (ports 0/1, and 16/17).
52215976Sjmallett** Ports 0 and 16 are the ports that are connected to the XAUI MACs (which are connected to the SFP+ modules)
53215976Sjmallett** Ports 1 and 17 are connected to the hairpin loopback port on the IXF SPI interface.  All packets sent out
54215976Sjmallett** of these ports are looped back the same port they were sent on.  The loopback ports are always enabled.
55215976Sjmallett**
56215976Sjmallett** The MAC address filtering on the IXF is not enabled.  Link up/down events are not detected, only SPI status
57215976Sjmallett** is monitored by default, which is independent of the XAUI/SFP+ link status.
58215976Sjmallett**
59215976Sjmallett**
60215976Sjmallett*/
61215976Sjmallett#include "cvmx.h"
62215976Sjmallett#include "cvmx-swap.h"
63215976Sjmallett
64215976Sjmallett
65215976Sjmallett
66215976Sjmallett
67215976Sjmallett
68215976Sjmallett#define PAL_BASE            (1ull << 63 | 0x1d030000)
69215976Sjmallett#define IXF_ADDR_HI         (PAL_BASE + 0xa)
70215976Sjmallett#define IXF_ADDR_LO         (PAL_BASE + 0xb)
71215976Sjmallett#define IXF_ADDR_16         IXF_ADDR_HI         /* 16 bit access */
72215976Sjmallett
73215976Sjmallett#define IXF_WR_DATA_HI      (PAL_BASE + 0xc)
74215976Sjmallett#define IXF_WR_DATA_LO      (PAL_BASE + 0xd)
75215976Sjmallett#define IXF_WR_DATA_16      IXF_WR_DATA_HI
76215976Sjmallett
77215976Sjmallett#define IXF_RD_DATA_HI      (PAL_BASE + 0x10)
78215976Sjmallett#define IXF_RD_DATA_LO      (PAL_BASE + 0x11)
79215976Sjmallett#define IXF_RD_DATA_16      IXF_RD_DATA_HI
80215976Sjmallett
81215976Sjmallett#define IXF_TRANS_TYPE      (PAL_BASE + 0xe)
82215976Sjmallett#define IXF_TRANS_STATUS    (PAL_BASE + 0xf)
83215976Sjmallett
84215976Sjmallett
85215976Sjmallettuint16_t cvmx_ixf18201_read16(uint16_t reg_addr)
86215976Sjmallett{
87215976Sjmallett    cvmx_write64_uint16(IXF_ADDR_16, reg_addr);
88215976Sjmallett    cvmx_write64_uint8(IXF_TRANS_TYPE, 1);  // Do read
89215976Sjmallett    cvmx_wait(800000);
90215976Sjmallett
91215976Sjmallett    /* Read result */
92215976Sjmallett    return(cvmx_read64_uint16(IXF_RD_DATA_16));
93215976Sjmallett}
94215976Sjmallett
95215976Sjmallettvoid cvmx_ixf18201_write16(uint16_t reg_addr, uint16_t data)
96215976Sjmallett{
97215976Sjmallett    cvmx_write64_uint16(IXF_ADDR_16, reg_addr);
98215976Sjmallett    cvmx_write64_uint16(IXF_WR_DATA_16, data);
99215976Sjmallett    cvmx_write64_uint8(IXF_TRANS_TYPE, 0);
100215976Sjmallett    cvmx_wait(800000);
101215976Sjmallett}
102215976Sjmallett
103215976Sjmallett
104215976Sjmallett
105215976Sjmallettuint32_t cvmx_ixf18201_read32(uint16_t reg_addr)
106215976Sjmallett{
107215976Sjmallett    uint32_t hi, lo;
108215976Sjmallett
109215976Sjmallett    if (reg_addr & 0x1)
110215976Sjmallett    {
111215976Sjmallett        return(0xdeadbeef);
112215976Sjmallett    }
113215976Sjmallett    lo = cvmx_ixf18201_read16(reg_addr);
114215976Sjmallett    hi = cvmx_ixf18201_read16(reg_addr + 1);
115215976Sjmallett    return((hi << 16) | lo);
116215976Sjmallett}
117215976Sjmallettvoid cvmx_ixf18201_write32(uint16_t reg_addr, uint32_t data)
118215976Sjmallett{
119215976Sjmallett    uint16_t hi, lo;
120215976Sjmallett
121215976Sjmallett    if (reg_addr & 0x1)
122215976Sjmallett    {
123215976Sjmallett        return;
124215976Sjmallett    }
125215976Sjmallett    lo = data & 0xFFFF;
126215976Sjmallett    hi = data >> 16;
127215976Sjmallett    cvmx_ixf18201_write16(reg_addr, lo);
128215976Sjmallett    cvmx_ixf18201_write16(reg_addr + 1, hi);
129215976Sjmallett
130215976Sjmallett}
131215976Sjmallett
132215976Sjmallett
133215976Sjmallett#define IXF_REG_MDI_CMD_ADDR1   0x310E
134215976Sjmallett#define IXF_REG_MDI_RD_WR1      0x3110
135215976Sjmallettvoid cvmx_ixf18201_mii_write(int mii_addr, int mmd, uint16_t reg, uint16_t val)
136215976Sjmallett{
137215976Sjmallett    uint32_t cmd_val = 0;
138215976Sjmallett
139215976Sjmallett
140215976Sjmallett    cmd_val = reg;
141215976Sjmallett    cmd_val |= 0x0 << 26;  // Set address operation
142215976Sjmallett    cmd_val |= (mii_addr & 0x1f) << 21;  // Set PHY addr
143215976Sjmallett    cmd_val |= (mmd & 0x1f) << 16;  // Set MMD
144215976Sjmallett    cmd_val |= 1 << 30;   // Do operation
145215976Sjmallett    cmd_val |= 1 << 31;   // enable in progress bit
146215976Sjmallett
147215976Sjmallett
148215976Sjmallett
149215976Sjmallett    /* Set up address */
150215976Sjmallett    cvmx_ixf18201_write32(IXF_REG_MDI_CMD_ADDR1, cmd_val);
151215976Sjmallett
152215976Sjmallett    while (cvmx_ixf18201_read32(IXF_REG_MDI_CMD_ADDR1) & ( 1 << 30))
153215976Sjmallett        ;  /* Wait for operation to complete */
154215976Sjmallett
155215976Sjmallett
156215976Sjmallett    cvmx_ixf18201_write32(IXF_REG_MDI_RD_WR1, val);
157215976Sjmallett
158215976Sjmallett    /* Do read operation */
159215976Sjmallett    cmd_val = 0;
160215976Sjmallett    cmd_val |= 0x1 << 26;  // Set write operation
161215976Sjmallett    cmd_val |= (mii_addr & 0x1f) << 21;  // Set PHY addr
162215976Sjmallett    cmd_val |= (mmd & 0x1f) << 16;  // Set MMD
163215976Sjmallett    cmd_val |= 1 << 30;   // Do operation
164215976Sjmallett    cmd_val |= 1 << 31;   // enable in progress bit
165215976Sjmallett    cvmx_ixf18201_write32(IXF_REG_MDI_CMD_ADDR1, cmd_val);
166215976Sjmallett
167215976Sjmallett    while (cvmx_ixf18201_read32(IXF_REG_MDI_CMD_ADDR1) & ( 1 << 30))
168215976Sjmallett        ;  /* Wait for operation to complete */
169215976Sjmallett
170215976Sjmallett
171215976Sjmallett}
172215976Sjmallett
173215976Sjmallett
174215976Sjmallettint cvmx_ixf18201_mii_read(int mii_addr, int mmd, uint16_t reg)
175215976Sjmallett{
176215976Sjmallett    uint32_t cmd_val = 0;
177215976Sjmallett
178215976Sjmallett
179215976Sjmallett    cmd_val = reg;
180215976Sjmallett    cmd_val |= 0x0 << 26;  // Set address operation
181215976Sjmallett    cmd_val |= (mii_addr & 0x1f) << 21;  // Set PHY addr
182215976Sjmallett    cmd_val |= (mmd & 0x1f) << 16;  // Set MMD
183215976Sjmallett    cmd_val |= 1 << 30;   // Do operation
184215976Sjmallett    cmd_val |= 1 << 31;   // enable in progress bit
185215976Sjmallett
186215976Sjmallett
187215976Sjmallett
188215976Sjmallett    /* Set up address */
189215976Sjmallett    cvmx_ixf18201_write32(IXF_REG_MDI_CMD_ADDR1, cmd_val);
190215976Sjmallett
191215976Sjmallett    while (cvmx_ixf18201_read32(IXF_REG_MDI_CMD_ADDR1) & ( 1 << 30))
192215976Sjmallett        ;  /* Wait for operation to complete */
193215976Sjmallett
194215976Sjmallett    /* Do read operation */
195215976Sjmallett    cmd_val = 0;
196215976Sjmallett    cmd_val |= 0x3 << 26;  // Set read operation
197215976Sjmallett    cmd_val |= (mii_addr & 0x1f) << 21;  // Set PHY addr
198215976Sjmallett    cmd_val |= (mmd & 0x1f) << 16;  // Set MMD
199215976Sjmallett    cmd_val |= 1 << 30;   // Do operation
200215976Sjmallett    cmd_val |= 1 << 31;   // enable in progress bit
201215976Sjmallett    cvmx_ixf18201_write32(IXF_REG_MDI_CMD_ADDR1, cmd_val);
202215976Sjmallett
203215976Sjmallett    while (cvmx_ixf18201_read32(IXF_REG_MDI_CMD_ADDR1) & ( 1 << 30))
204215976Sjmallett        ;  /* Wait for operation to complete */
205215976Sjmallett
206215976Sjmallett    cmd_val = cvmx_ixf18201_read32(IXF_REG_MDI_RD_WR1);
207215976Sjmallett
208215976Sjmallett    return(cmd_val >> 16);
209215976Sjmallett
210215976Sjmallett}
211215976Sjmallett
212215976Sjmallett
213215976Sjmallett
214215976Sjmallettint cvmx_ixf18201_init(void)
215215976Sjmallett{
216215976Sjmallett    int index;  /* For indexing the two 'ports' on ixf */
217215976Sjmallett    int offset;
218215976Sjmallett
219215976Sjmallett    /* Reset IXF, and take all blocks out of reset */
220215976Sjmallett
221215976Sjmallett/*
222215976SjmallettInitializing...
223215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0003, old: 0x0000, new: 0x0001
224215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0003, old: 0x0001, new: 0x0000
225215976SjmallettPP0:~CONSOLE->  **** LLM201(Lochlomond) Driver loaded ****
226215976SjmallettPP0:~CONSOLE->  LLM201 Driver - Released on Tue Aug 28 09:51:30 2007.
227215976SjmallettPP0:~CONSOLE-> retval is: 0
228215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0003, old: 0x0000, new: 0x0001
229215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0003, old: 0x0001, new: 0x0000
230215976SjmallettPP0:~CONSOLE-> Brought all blocks out of reset
231215976SjmallettPP0:~CONSOLE-> Getting default config.
232215976Sjmallett*/
233215976Sjmallett
234215976Sjmallett
235215976Sjmallett    cvmx_ixf18201_write16(0x0003, 0x0001);
236215976Sjmallett    cvmx_ixf18201_write16(0x0003, 0);
237215976Sjmallett
238215976Sjmallett    /*
239215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0000, old: 0x4014, new: 0x4010
240215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0000, old: 0x4010, new: 0x4014
241215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0004, old: 0x01ff, new: 0x0140
242215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0009, old: 0x007f, new: 0x0000
243215976Sjmallett    */
244215976Sjmallett    cvmx_ixf18201_write16(0x0000, 0x4010);
245215976Sjmallett    cvmx_ixf18201_write16(0x0000, 0x4014);
246215976Sjmallett    cvmx_ixf18201_write16(0x0004, 0x0140);
247215976Sjmallett    cvmx_ixf18201_write16(0x0009, 0);
248215976Sjmallett
249215976Sjmallett
250215976Sjmallett    /*
251215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x000e, old: 0x0000, new: 0x000f
252215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x000f, old: 0x0000, new: 0x0004
253215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x000f, old: 0x0004, new: 0x0006
254215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x000e, old: 0x000f, new: 0x00f0
255215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x000f, old: 0x0006, new: 0x0040
256215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x000f, old: 0x0040, new: 0x0060
257215976Sjmallett    */
258215976Sjmallett    // skip GPIO, 0xe/0xf
259215976Sjmallett
260215976Sjmallett
261215976Sjmallett    /*
262215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3100, old: 0x57fb, new: 0x7f7b
263215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3600, old: 0x57fb, new: 0x7f7b
264215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3005, old: 0x8010, new: 0x0040
265215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3006, old: 0x061a, new: 0x0000
266215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3505, old: 0x8010, new: 0x0040
267215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3506, old: 0x061a, new: 0x0000
268215976Sjmallett    */
269215976Sjmallett    for (index = 0; index < 2;index++ )
270215976Sjmallett    {
271215976Sjmallett        offset = 0x500 * index;
272215976Sjmallett        cvmx_ixf18201_write32(0x3100 + offset, 0x47f7b);
273215976Sjmallett        cvmx_ixf18201_write16(0x3005 + offset, 0x0040);
274215976Sjmallett        cvmx_ixf18201_write16(0x3006 + offset, 0);
275215976Sjmallett    }
276215976Sjmallett
277215976Sjmallett    /*PP0:~CONSOLE->   *** SPI soft reset ***, block id: 0
278215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3007, old: 0xf980, new: 0xf9c0
279215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3008, old: 0xa6f0, new: 0x36f0
280215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3000, old: 0x0080, new: 0x0060
281215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3002, old: 0x0200, new: 0x0040
282215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3003, old: 0x0100, new: 0x0000
283215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x30c2, old: 0x0080, new: 0x0060
284215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x300a, old: 0x0800, new: 0x0000
285215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3007, old: 0xf9c0, new: 0x89c0
286215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3016, old: 0x0000, new: 0x0010
287215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3008, old: 0x36f0, new: 0x3610
288215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3012, old: 0x0000, new: 0x0010
289215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3007, old: 0x89c0, new: 0x8980
290215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3008, old: 0x3610, new: 0xa210
291215976SjmallettPP0:~CONSOLE->
292215976Sjmallett
293215976Sjmallett    */
294215976Sjmallett
295215976Sjmallett
296215976Sjmallett    for (index = 0; index < 2;index++ )
297215976Sjmallett    {
298215976Sjmallett        offset = 0x500 * index;
299215976Sjmallett        int cal_len_min_1 = 0;  /* Calendar length -1.  Must match number
300215976Sjmallett                                ** of ports configured for interface.*/
301215976Sjmallett        cvmx_ixf18201_write16(0x3007 + offset, 0x81c0 | (cal_len_min_1 << 11));
302215976Sjmallett        cvmx_ixf18201_write16(0x3008 + offset, 0x3600 | (cal_len_min_1 << 4));
303215976Sjmallett        cvmx_ixf18201_write16(0x3000 + offset, 0x0060);
304215976Sjmallett        cvmx_ixf18201_write16(0x3002 + offset, 0x0040);
305215976Sjmallett        cvmx_ixf18201_write16(0x3003 + offset, 0x0000);
306215976Sjmallett        cvmx_ixf18201_write16(0x30c2 + offset, 0x0060);
307215976Sjmallett        cvmx_ixf18201_write16(0x300a + offset, 0x0000);
308215976Sjmallett        cvmx_ixf18201_write16(0x3007 + offset, 0x81c0 | (cal_len_min_1 << 11));
309215976Sjmallett        cvmx_ixf18201_write16(0x3016 + offset, 0x0010);
310215976Sjmallett        cvmx_ixf18201_write16(0x3008 + offset, 0x3600 | (cal_len_min_1 << 4));
311215976Sjmallett        cvmx_ixf18201_write16(0x3012 + offset, 0x0010);
312215976Sjmallett        cvmx_ixf18201_write16(0x3007 + offset, 0x8180 | (cal_len_min_1 << 11));
313215976Sjmallett        cvmx_ixf18201_write16(0x3008 + offset, 0xa200 | (cal_len_min_1 << 4));
314215976Sjmallett
315215976Sjmallett        cvmx_ixf18201_write16(0x3090 + offset, 0x0301);  /* Enable hairpin loopback */
316215976Sjmallett    }
317215976Sjmallett
318215976Sjmallett
319215976Sjmallett
320215976Sjmallett    /*
321215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0004, old: 0x0140, new: 0x1fff
322215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x0009, old: 0x0000, new: 0x007f
323215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x310b, old: 0x0004, new: 0xffff
324215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x310a, old: 0x7f7b, new: 0xffff
325215976Sjmallett
326215976Sjmallett    */
327215976Sjmallett
328215976Sjmallett    cvmx_ixf18201_write16(0x0004, 0x1fff);
329215976Sjmallett    cvmx_ixf18201_write16(0x0009, 0x007f);
330215976Sjmallett#if 0
331215976Sjmallett    /* MDI autoscan */
332215976Sjmallett    cvmx_ixf18201_write16(0x310b, 0xffff);
333215976Sjmallett    cvmx_ixf18201_write16(0x310a, 0xffff);
334215976Sjmallett#endif
335215976Sjmallett
336215976Sjmallett
337215976Sjmallett    /*
338215976Sjmallett    *** 32 bit register, trace only captures part of it...
339215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3100, old: 0x7f7b, new: 0x7f78
340215976SjmallettPP0:~CONSOLE-> Changing register value, addr 0x3600, old: 0x7f7b, new: 0x7f78
341215976Sjmallett    */
342215976Sjmallett
343215976Sjmallett    for (index = 0; index < 2;index++ )
344215976Sjmallett    {
345215976Sjmallett        offset = 0x500 * index;
346215976Sjmallett        cvmx_ixf18201_write32(0x3100 + offset, 0x47f7c); /* Also enable jumbo frames */
347215976Sjmallett        /* Set max packet size to 9600 bytes, max supported by IXF18201 */
348215976Sjmallett        cvmx_ixf18201_write32(0x3114 + offset, 0x25800000);
349215976Sjmallett    }
350215976Sjmallett
351215976Sjmallett
352215976Sjmallett    cvmx_wait(100000000);
353215976Sjmallett
354215976Sjmallett    /* Now reset the PCS blocks in the phy.  This seems to be required after
355215976Sjmallett    ** bringing up the Cortina. */
356215976Sjmallett    cvmx_ixf18201_mii_write(1, 3, 0, 0x8000);
357215976Sjmallett    cvmx_ixf18201_mii_write(5, 3, 0, 0x8000);
358215976Sjmallett
359215976Sjmallett
360215976Sjmallett    return 1;
361215976Sjmallett
362215976Sjmallett}
363