aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/cavium-octeon/executive
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/cavium-octeon/executive')
-rw-r--r--arch/mips/cavium-octeon/executive/Makefile7
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c306
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-fpa.c183
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-board.c691
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c243
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-loop.c85
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-npi.c113
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c526
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c550
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-spi.c195
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-util.c433
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c348
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper.c1053
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c371
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c140
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-pko.c506
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-spi.c667
17 files changed, 6416 insertions, 1 deletions
diff --git a/arch/mips/cavium-octeon/executive/Makefile b/arch/mips/cavium-octeon/executive/Makefile
index 7f41c5be2190..b6d6e841a984 100644
--- a/arch/mips/cavium-octeon/executive/Makefile
+++ b/arch/mips/cavium-octeon/executive/Makefile
@@ -10,5 +10,10 @@
10# 10#
11 11
12obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o 12obj-y += cvmx-bootmem.o cvmx-l2c.o cvmx-sysinfo.o octeon-model.o
13obj-y += cvmx-pko.o cvmx-spi.o cvmx-cmd-queue.o \
14 cvmx-helper-board.o cvmx-helper.o cvmx-helper-xaui.o \
15 cvmx-helper-rgmii.o cvmx-helper-sgmii.o cvmx-helper-npi.o \
16 cvmx-helper-loop.o cvmx-helper-spi.o cvmx-helper-util.o \
17 cvmx-interrupt-decodes.o cvmx-interrupt-rsl.o
13 18
14obj-$(CONFIG_CAVIUM_OCTEON_HELPER) += cvmx-helper-errata.o cvmx-helper-jtag.o 19obj-y += cvmx-helper-errata.o cvmx-helper-jtag.o
diff --git a/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
new file mode 100644
index 000000000000..132bccc66a93
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
@@ -0,0 +1,306 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Support functions for managing command queues used for
30 * various hardware blocks.
31 */
32
33#include <linux/kernel.h>
34
35#include <asm/octeon/octeon.h>
36
37#include <asm/octeon/cvmx-config.h>
38#include <asm/octeon/cvmx-fpa.h>
39#include <asm/octeon/cvmx-cmd-queue.h>
40
41#include <asm/octeon/cvmx-npei-defs.h>
42#include <asm/octeon/cvmx-pexp-defs.h>
43#include <asm/octeon/cvmx-pko-defs.h>
44
45/**
46 * This application uses this pointer to access the global queue
47 * state. It points to a bootmem named block.
48 */
49__cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr;
50
51/**
52 * Initialize the Global queue state pointer.
53 *
54 * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code
55 */
56static cvmx_cmd_queue_result_t __cvmx_cmd_queue_init_state_ptr(void)
57{
58 char *alloc_name = "cvmx_cmd_queues";
59#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32
60 extern uint64_t octeon_reserve32_memory;
61#endif
62
63 if (likely(__cvmx_cmd_queue_state_ptr))
64 return CVMX_CMD_QUEUE_SUCCESS;
65
66#if defined(CONFIG_CAVIUM_RESERVE32) && CONFIG_CAVIUM_RESERVE32
67 if (octeon_reserve32_memory)
68 __cvmx_cmd_queue_state_ptr =
69 cvmx_bootmem_alloc_named_range(sizeof(*__cvmx_cmd_queue_state_ptr),
70 octeon_reserve32_memory,
71 octeon_reserve32_memory +
72 (CONFIG_CAVIUM_RESERVE32 <<
73 20) - 1, 128, alloc_name);
74 else
75#endif
76 __cvmx_cmd_queue_state_ptr =
77 cvmx_bootmem_alloc_named(sizeof(*__cvmx_cmd_queue_state_ptr),
78 128,
79 alloc_name);
80 if (__cvmx_cmd_queue_state_ptr)
81 memset(__cvmx_cmd_queue_state_ptr, 0,
82 sizeof(*__cvmx_cmd_queue_state_ptr));
83 else {
84 struct cvmx_bootmem_named_block_desc *block_desc =
85 cvmx_bootmem_find_named_block(alloc_name);
86 if (block_desc)
87 __cvmx_cmd_queue_state_ptr =
88 cvmx_phys_to_ptr(block_desc->base_addr);
89 else {
90 cvmx_dprintf
91 ("ERROR: cvmx_cmd_queue_initialize: Unable to get named block %s.\n",
92 alloc_name);
93 return CVMX_CMD_QUEUE_NO_MEMORY;
94 }
95 }
96 return CVMX_CMD_QUEUE_SUCCESS;
97}
98
99/**
100 * Initialize a command queue for use. The initial FPA buffer is
101 * allocated and the hardware unit is configured to point to the
102 * new command queue.
103 *
104 * @queue_id: Hardware command queue to initialize.
105 * @max_depth: Maximum outstanding commands that can be queued.
106 * @fpa_pool: FPA pool the command queues should come from.
107 * @pool_size: Size of each buffer in the FPA pool (bytes)
108 *
109 * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code
110 */
111cvmx_cmd_queue_result_t cvmx_cmd_queue_initialize(cvmx_cmd_queue_id_t queue_id,
112 int max_depth, int fpa_pool,
113 int pool_size)
114{
115 __cvmx_cmd_queue_state_t *qstate;
116 cvmx_cmd_queue_result_t result = __cvmx_cmd_queue_init_state_ptr();
117 if (result != CVMX_CMD_QUEUE_SUCCESS)
118 return result;
119
120 qstate = __cvmx_cmd_queue_get_state(queue_id);
121 if (qstate == NULL)
122 return CVMX_CMD_QUEUE_INVALID_PARAM;
123
124 /*
125 * We artificially limit max_depth to 1<<20 words. It is an
126 * arbitrary limit.
127 */
128 if (CVMX_CMD_QUEUE_ENABLE_MAX_DEPTH) {
129 if ((max_depth < 0) || (max_depth > 1 << 20))
130 return CVMX_CMD_QUEUE_INVALID_PARAM;
131 } else if (max_depth != 0)
132 return CVMX_CMD_QUEUE_INVALID_PARAM;
133
134 if ((fpa_pool < 0) || (fpa_pool > 7))
135 return CVMX_CMD_QUEUE_INVALID_PARAM;
136 if ((pool_size < 128) || (pool_size > 65536))
137 return CVMX_CMD_QUEUE_INVALID_PARAM;
138
139 /* See if someone else has already initialized the queue */
140 if (qstate->base_ptr_div128) {
141 if (max_depth != (int)qstate->max_depth) {
142 cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
143 "Queue already initialized with different "
144 "max_depth (%d).\n",
145 (int)qstate->max_depth);
146 return CVMX_CMD_QUEUE_INVALID_PARAM;
147 }
148 if (fpa_pool != qstate->fpa_pool) {
149 cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
150 "Queue already initialized with different "
151 "FPA pool (%u).\n",
152 qstate->fpa_pool);
153 return CVMX_CMD_QUEUE_INVALID_PARAM;
154 }
155 if ((pool_size >> 3) - 1 != qstate->pool_size_m1) {
156 cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
157 "Queue already initialized with different "
158 "FPA pool size (%u).\n",
159 (qstate->pool_size_m1 + 1) << 3);
160 return CVMX_CMD_QUEUE_INVALID_PARAM;
161 }
162 CVMX_SYNCWS;
163 return CVMX_CMD_QUEUE_ALREADY_SETUP;
164 } else {
165 union cvmx_fpa_ctl_status status;
166 void *buffer;
167
168 status.u64 = cvmx_read_csr(CVMX_FPA_CTL_STATUS);
169 if (!status.s.enb) {
170 cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
171 "FPA is not enabled.\n");
172 return CVMX_CMD_QUEUE_NO_MEMORY;
173 }
174 buffer = cvmx_fpa_alloc(fpa_pool);
175 if (buffer == NULL) {
176 cvmx_dprintf("ERROR: cvmx_cmd_queue_initialize: "
177 "Unable to allocate initial buffer.\n");
178 return CVMX_CMD_QUEUE_NO_MEMORY;
179 }
180
181 memset(qstate, 0, sizeof(*qstate));
182 qstate->max_depth = max_depth;
183 qstate->fpa_pool = fpa_pool;
184 qstate->pool_size_m1 = (pool_size >> 3) - 1;
185 qstate->base_ptr_div128 = cvmx_ptr_to_phys(buffer) / 128;
186 /*
187 * We zeroed the now serving field so we need to also
188 * zero the ticket.
189 */
190 __cvmx_cmd_queue_state_ptr->
191 ticket[__cvmx_cmd_queue_get_index(queue_id)] = 0;
192 CVMX_SYNCWS;
193 return CVMX_CMD_QUEUE_SUCCESS;
194 }
195}
196
197/**
198 * Shutdown a queue a free it's command buffers to the FPA. The
199 * hardware connected to the queue must be stopped before this
200 * function is called.
201 *
202 * @queue_id: Queue to shutdown
203 *
204 * Returns CVMX_CMD_QUEUE_SUCCESS or a failure code
205 */
206cvmx_cmd_queue_result_t cvmx_cmd_queue_shutdown(cvmx_cmd_queue_id_t queue_id)
207{
208 __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
209 if (qptr == NULL) {
210 cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Unable to "
211 "get queue information.\n");
212 return CVMX_CMD_QUEUE_INVALID_PARAM;
213 }
214
215 if (cvmx_cmd_queue_length(queue_id) > 0) {
216 cvmx_dprintf("ERROR: cvmx_cmd_queue_shutdown: Queue still "
217 "has data in it.\n");
218 return CVMX_CMD_QUEUE_FULL;
219 }
220
221 __cvmx_cmd_queue_lock(queue_id, qptr);
222 if (qptr->base_ptr_div128) {
223 cvmx_fpa_free(cvmx_phys_to_ptr
224 ((uint64_t) qptr->base_ptr_div128 << 7),
225 qptr->fpa_pool, 0);
226 qptr->base_ptr_div128 = 0;
227 }
228 __cvmx_cmd_queue_unlock(qptr);
229
230 return CVMX_CMD_QUEUE_SUCCESS;
231}
232
233/**
234 * Return the number of command words pending in the queue. This
235 * function may be relatively slow for some hardware units.
236 *
237 * @queue_id: Hardware command queue to query
238 *
239 * Returns Number of outstanding commands
240 */
241int cvmx_cmd_queue_length(cvmx_cmd_queue_id_t queue_id)
242{
243 if (CVMX_ENABLE_PARAMETER_CHECKING) {
244 if (__cvmx_cmd_queue_get_state(queue_id) == NULL)
245 return CVMX_CMD_QUEUE_INVALID_PARAM;
246 }
247
248 /*
249 * The cast is here so gcc with check that all values in the
250 * cvmx_cmd_queue_id_t enumeration are here.
251 */
252 switch ((cvmx_cmd_queue_id_t) (queue_id & 0xff0000)) {
253 case CVMX_CMD_QUEUE_PKO_BASE:
254 /*
255 * FIXME: Need atomic lock on
256 * CVMX_PKO_REG_READ_IDX. Right now we are normally
257 * called with the queue lock, so that is a SLIGHT
258 * amount of protection.
259 */
260 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue_id & 0xffff);
261 if (OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
262 union cvmx_pko_mem_debug9 debug9;
263 debug9.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG9);
264 return debug9.cn38xx.doorbell;
265 } else {
266 union cvmx_pko_mem_debug8 debug8;
267 debug8.u64 = cvmx_read_csr(CVMX_PKO_MEM_DEBUG8);
268 return debug8.cn58xx.doorbell;
269 }
270 case CVMX_CMD_QUEUE_ZIP:
271 case CVMX_CMD_QUEUE_DFA:
272 case CVMX_CMD_QUEUE_RAID:
273 /* FIXME: Implement other lengths */
274 return 0;
275 case CVMX_CMD_QUEUE_DMA_BASE:
276 {
277 union cvmx_npei_dmax_counts dmax_counts;
278 dmax_counts.u64 =
279 cvmx_read_csr(CVMX_PEXP_NPEI_DMAX_COUNTS
280 (queue_id & 0x7));
281 return dmax_counts.s.dbell;
282 }
283 case CVMX_CMD_QUEUE_END:
284 return CVMX_CMD_QUEUE_INVALID_PARAM;
285 }
286 return CVMX_CMD_QUEUE_INVALID_PARAM;
287}
288
289/**
290 * Return the command buffer to be written to. The purpose of this
291 * function is to allow CVMX routine access t othe low level buffer
292 * for initial hardware setup. User applications should not call this
293 * function directly.
294 *
295 * @queue_id: Command queue to query
296 *
297 * Returns Command buffer or NULL on failure
298 */
299void *cvmx_cmd_queue_buffer(cvmx_cmd_queue_id_t queue_id)
300{
301 __cvmx_cmd_queue_state_t *qptr = __cvmx_cmd_queue_get_state(queue_id);
302 if (qptr && qptr->base_ptr_div128)
303 return cvmx_phys_to_ptr((uint64_t) qptr->base_ptr_div128 << 7);
304 else
305 return NULL;
306}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-fpa.c
new file mode 100644
index 000000000000..ad44b8bd8057
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-fpa.c
@@ -0,0 +1,183 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/**
29 * @file
30 *
31 * Support library for the hardware Free Pool Allocator.
32 *
33 *
34 */
35
36#include "cvmx-config.h"
37#include "cvmx.h"
38#include "cvmx-fpa.h"
39#include "cvmx-ipd.h"
40
41/**
42 * Current state of all the pools. Use access functions
43 * instead of using it directly.
44 */
45CVMX_SHARED cvmx_fpa_pool_info_t cvmx_fpa_pool_info[CVMX_FPA_NUM_POOLS];
46
47/**
48 * Setup a FPA pool to control a new block of memory. The
49 * buffer pointer must be a physical address.
50 *
51 * @pool: Pool to initialize
52 * 0 <= pool < 8
53 * @name: Constant character string to name this pool.
54 * String is not copied.
55 * @buffer: Pointer to the block of memory to use. This must be
56 * accessible by all processors and external hardware.
57 * @block_size: Size for each block controlled by the FPA
58 * @num_blocks: Number of blocks
59 *
60 * Returns 0 on Success,
61 * -1 on failure
62 */
63int cvmx_fpa_setup_pool(uint64_t pool, const char *name, void *buffer,
64 uint64_t block_size, uint64_t num_blocks)
65{
66 char *ptr;
67 if (!buffer) {
68 cvmx_dprintf
69 ("ERROR: cvmx_fpa_setup_pool: NULL buffer pointer!\n");
70 return -1;
71 }
72 if (pool >= CVMX_FPA_NUM_POOLS) {
73 cvmx_dprintf("ERROR: cvmx_fpa_setup_pool: Illegal pool!\n");
74 return -1;
75 }
76
77 if (block_size < CVMX_FPA_MIN_BLOCK_SIZE) {
78 cvmx_dprintf
79 ("ERROR: cvmx_fpa_setup_pool: Block size too small.\n");
80 return -1;
81 }
82
83 if (((unsigned long)buffer & (CVMX_FPA_ALIGNMENT - 1)) != 0) {
84 cvmx_dprintf
85 ("ERROR: cvmx_fpa_setup_pool: Buffer not aligned properly.\n");
86 return -1;
87 }
88
89 cvmx_fpa_pool_info[pool].name = name;
90 cvmx_fpa_pool_info[pool].size = block_size;
91 cvmx_fpa_pool_info[pool].starting_element_count = num_blocks;
92 cvmx_fpa_pool_info[pool].base = buffer;
93
94 ptr = (char *)buffer;
95 while (num_blocks--) {
96 cvmx_fpa_free(ptr, pool, 0);
97 ptr += block_size;
98 }
99 return 0;
100}
101
102/**
103 * Shutdown a Memory pool and validate that it had all of
104 * the buffers originally placed in it.
105 *
106 * @pool: Pool to shutdown
107 * Returns Zero on success
108 * - Positive is count of missing buffers
109 * - Negative is too many buffers or corrupted pointers
110 */
111uint64_t cvmx_fpa_shutdown_pool(uint64_t pool)
112{
113 uint64_t errors = 0;
114 uint64_t count = 0;
115 uint64_t base = cvmx_ptr_to_phys(cvmx_fpa_pool_info[pool].base);
116 uint64_t finish =
117 base +
118 cvmx_fpa_pool_info[pool].size *
119 cvmx_fpa_pool_info[pool].starting_element_count;
120 void *ptr;
121 uint64_t address;
122
123 count = 0;
124 do {
125 ptr = cvmx_fpa_alloc(pool);
126 if (ptr)
127 address = cvmx_ptr_to_phys(ptr);
128 else
129 address = 0;
130 if (address) {
131 if ((address >= base) && (address < finish) &&
132 (((address -
133 base) % cvmx_fpa_pool_info[pool].size) == 0)) {
134 count++;
135 } else {
136 cvmx_dprintf
137 ("ERROR: cvmx_fpa_shutdown_pool: Illegal address 0x%llx in pool %s(%d)\n",
138 (unsigned long long)address,
139 cvmx_fpa_pool_info[pool].name, (int)pool);
140 errors++;
141 }
142 }
143 } while (address);
144
145#ifdef CVMX_ENABLE_PKO_FUNCTIONS
146 if (pool == 0)
147 cvmx_ipd_free_ptr();
148#endif
149
150 if (errors) {
151 cvmx_dprintf
152 ("ERROR: cvmx_fpa_shutdown_pool: Pool %s(%d) started at 0x%llx, ended at 0x%llx, with a step of 0x%llx\n",
153 cvmx_fpa_pool_info[pool].name, (int)pool,
154 (unsigned long long)base, (unsigned long long)finish,
155 (unsigned long long)cvmx_fpa_pool_info[pool].size);
156 return -errors;
157 } else
158 return 0;
159}
160
161uint64_t cvmx_fpa_get_block_size(uint64_t pool)
162{
163 switch (pool) {
164 case 0:
165 return CVMX_FPA_POOL_0_SIZE;
166 case 1:
167 return CVMX_FPA_POOL_1_SIZE;
168 case 2:
169 return CVMX_FPA_POOL_2_SIZE;
170 case 3:
171 return CVMX_FPA_POOL_3_SIZE;
172 case 4:
173 return CVMX_FPA_POOL_4_SIZE;
174 case 5:
175 return CVMX_FPA_POOL_5_SIZE;
176 case 6:
177 return CVMX_FPA_POOL_6_SIZE;
178 case 7:
179 return CVMX_FPA_POOL_7_SIZE;
180 default:
181 return 0;
182 }
183}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
new file mode 100644
index 000000000000..71590a35163b
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
@@ -0,0 +1,691 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 *
30 * Helper functions to abstract board specific data about
31 * network ports from the rest of the cvmx-helper files.
32 */
33
34#include <asm/octeon/octeon.h>
35#include <asm/octeon/cvmx-bootinfo.h>
36
37#include <asm/octeon/cvmx-config.h>
38
39#include <asm/octeon/cvmx-mdio.h>
40
41#include <asm/octeon/cvmx-helper.h>
42#include <asm/octeon/cvmx-helper-util.h>
43#include <asm/octeon/cvmx-helper-board.h>
44
45#include <asm/octeon/cvmx-gmxx-defs.h>
46#include <asm/octeon/cvmx-asxx-defs.h>
47
48/**
49 * cvmx_override_board_link_get(int ipd_port) is a function
50 * pointer. It is meant to allow customization of the process of
51 * talking to a PHY to determine link speed. It is called every
52 * time a PHY must be polled for link status. Users should set
53 * this pointer to a function before calling any cvmx-helper
54 * operations.
55 */
56cvmx_helper_link_info_t(*cvmx_override_board_link_get) (int ipd_port) =
57 NULL;
58
59/**
60 * Return the MII PHY address associated with the given IPD
61 * port. A result of -1 means there isn't a MII capable PHY
62 * connected to this port. On chips supporting multiple MII
63 * busses the bus number is encoded in bits <15:8>.
64 *
65 * This function must be modified for every new Octeon board.
66 * Internally it uses switch statements based on the cvmx_sysinfo
67 * data to determine board types and revisions. It replies on the
68 * fact that every Octeon board receives a unique board type
69 * enumeration from the bootloader.
70 *
71 * @ipd_port: Octeon IPD port to get the MII address for.
72 *
73 * Returns MII PHY address and bus number or -1.
74 */
75int cvmx_helper_board_get_mii_address(int ipd_port)
76{
77 switch (cvmx_sysinfo_get()->board_type) {
78 case CVMX_BOARD_TYPE_SIM:
79 /* Simulator doesn't have MII */
80 return -1;
81 case CVMX_BOARD_TYPE_EBT3000:
82 case CVMX_BOARD_TYPE_EBT5800:
83 case CVMX_BOARD_TYPE_THUNDER:
84 case CVMX_BOARD_TYPE_NICPRO2:
85 /* Interface 0 is SPI4, interface 1 is RGMII */
86 if ((ipd_port >= 16) && (ipd_port < 20))
87 return ipd_port - 16;
88 else
89 return -1;
90 case CVMX_BOARD_TYPE_KODAMA:
91 case CVMX_BOARD_TYPE_EBH3100:
92 case CVMX_BOARD_TYPE_HIKARI:
93 case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
94 case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
95 case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
96 /*
97 * Port 0 is WAN connected to a PHY, Port 1 is GMII
98 * connected to a switch
99 */
100 if (ipd_port == 0)
101 return 4;
102 else if (ipd_port == 1)
103 return 9;
104 else
105 return -1;
106 case CVMX_BOARD_TYPE_NAC38:
107 /* Board has 8 RGMII ports PHYs are 0-7 */
108 if ((ipd_port >= 0) && (ipd_port < 4))
109 return ipd_port;
110 else if ((ipd_port >= 16) && (ipd_port < 20))
111 return ipd_port - 16 + 4;
112 else
113 return -1;
114 case CVMX_BOARD_TYPE_EBH3000:
115 /* Board has dual SPI4 and no PHYs */
116 return -1;
117 case CVMX_BOARD_TYPE_EBH5200:
118 case CVMX_BOARD_TYPE_EBH5201:
119 case CVMX_BOARD_TYPE_EBT5200:
120 /*
121 * Board has 4 SGMII ports. The PHYs start right after the MII
122 * ports MII0 = 0, MII1 = 1, SGMII = 2-5.
123 */
124 if ((ipd_port >= 0) && (ipd_port < 4))
125 return ipd_port + 2;
126 else
127 return -1;
128 case CVMX_BOARD_TYPE_EBH5600:
129 case CVMX_BOARD_TYPE_EBH5601:
130 case CVMX_BOARD_TYPE_EBH5610:
131 /*
132 * Board has 8 SGMII ports. 4 connect out, two connect
133 * to a switch, and 2 loop to each other
134 */
135 if ((ipd_port >= 0) && (ipd_port < 4))
136 return ipd_port + 1;
137 else
138 return -1;
139 case CVMX_BOARD_TYPE_CUST_NB5:
140 if (ipd_port == 2)
141 return 4;
142 else
143 return -1;
144 case CVMX_BOARD_TYPE_NIC_XLE_4G:
145 /* Board has 4 SGMII ports. connected QLM3(interface 1) */
146 if ((ipd_port >= 16) && (ipd_port < 20))
147 return ipd_port - 16 + 1;
148 else
149 return -1;
150 case CVMX_BOARD_TYPE_BBGW_REF:
151 /*
152 * No PHYs are connected to Octeon, everything is
153 * through switch.
154 */
155 return -1;
156
157 case CVMX_BOARD_TYPE_CUST_WSX16:
158 if (ipd_port >= 0 && ipd_port <= 3)
159 return ipd_port;
160 else if (ipd_port >= 16 && ipd_port <= 19)
161 return ipd_port - 16 + 4;
162 else
163 return -1;
164 }
165
166 /* Some unknown board. Somebody forgot to update this function... */
167 cvmx_dprintf
168 ("cvmx_helper_board_get_mii_address: Unknown board type %d\n",
169 cvmx_sysinfo_get()->board_type);
170 return -1;
171}
172
173/**
174 * This function is the board specific method of determining an
175 * ethernet ports link speed. Most Octeon boards have Marvell PHYs
176 * and are handled by the fall through case. This function must be
177 * updated for boards that don't have the normal Marvell PHYs.
178 *
179 * This function must be modified for every new Octeon board.
180 * Internally it uses switch statements based on the cvmx_sysinfo
181 * data to determine board types and revisions. It relies on the
182 * fact that every Octeon board receives a unique board type
183 * enumeration from the bootloader.
184 *
185 * @ipd_port: IPD input port associated with the port we want to get link
186 * status for.
187 *
188 * Returns The ports link status. If the link isn't fully resolved, this must
189 * return zero.
190 */
191cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
192{
193 cvmx_helper_link_info_t result;
194 int phy_addr;
195 int is_broadcom_phy = 0;
196
197 /* Give the user a chance to override the processing of this function */
198 if (cvmx_override_board_link_get)
199 return cvmx_override_board_link_get(ipd_port);
200
201 /* Unless we fix it later, all links are defaulted to down */
202 result.u64 = 0;
203
204 /*
205 * This switch statement should handle all ports that either don't use
206 * Marvell PHYS, or don't support in-band status.
207 */
208 switch (cvmx_sysinfo_get()->board_type) {
209 case CVMX_BOARD_TYPE_SIM:
210 /* The simulator gives you a simulated 1Gbps full duplex link */
211 result.s.link_up = 1;
212 result.s.full_duplex = 1;
213 result.s.speed = 1000;
214 return result;
215 case CVMX_BOARD_TYPE_EBH3100:
216 case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
217 case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
218 case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
219 /* Port 1 on these boards is always Gigabit */
220 if (ipd_port == 1) {
221 result.s.link_up = 1;
222 result.s.full_duplex = 1;
223 result.s.speed = 1000;
224 return result;
225 }
226 /* Fall through to the generic code below */
227 break;
228 case CVMX_BOARD_TYPE_CUST_NB5:
229 /* Port 1 on these boards is always Gigabit */
230 if (ipd_port == 1) {
231 result.s.link_up = 1;
232 result.s.full_duplex = 1;
233 result.s.speed = 1000;
234 return result;
235 } else /* The other port uses a broadcom PHY */
236 is_broadcom_phy = 1;
237 break;
238 case CVMX_BOARD_TYPE_BBGW_REF:
239 /* Port 1 on these boards is always Gigabit */
240 if (ipd_port == 2) {
241 /* Port 2 is not hooked up */
242 result.u64 = 0;
243 return result;
244 } else {
245 /* Ports 0 and 1 connect to the switch */
246 result.s.link_up = 1;
247 result.s.full_duplex = 1;
248 result.s.speed = 1000;
249 return result;
250 }
251 break;
252 }
253
254 phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
255 if (phy_addr != -1) {
256 if (is_broadcom_phy) {
257 /*
258 * Below we are going to read SMI/MDIO
259 * register 0x19 which works on Broadcom
260 * parts
261 */
262 int phy_status =
263 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
264 0x19);
265 switch ((phy_status >> 8) & 0x7) {
266 case 0:
267 result.u64 = 0;
268 break;
269 case 1:
270 result.s.link_up = 1;
271 result.s.full_duplex = 0;
272 result.s.speed = 10;
273 break;
274 case 2:
275 result.s.link_up = 1;
276 result.s.full_duplex = 1;
277 result.s.speed = 10;
278 break;
279 case 3:
280 result.s.link_up = 1;
281 result.s.full_duplex = 0;
282 result.s.speed = 100;
283 break;
284 case 4:
285 result.s.link_up = 1;
286 result.s.full_duplex = 1;
287 result.s.speed = 100;
288 break;
289 case 5:
290 result.s.link_up = 1;
291 result.s.full_duplex = 1;
292 result.s.speed = 100;
293 break;
294 case 6:
295 result.s.link_up = 1;
296 result.s.full_duplex = 0;
297 result.s.speed = 1000;
298 break;
299 case 7:
300 result.s.link_up = 1;
301 result.s.full_duplex = 1;
302 result.s.speed = 1000;
303 break;
304 }
305 } else {
306 /*
307 * This code assumes we are using a Marvell
308 * Gigabit PHY. All the speed information can
309 * be read from register 17 in one
310 * go. Somebody using a different PHY will
311 * need to handle it above in the board
312 * specific area.
313 */
314 int phy_status =
315 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
316
317 /*
318 * If the resolve bit 11 isn't set, see if
319 * autoneg is turned off (bit 12, reg 0). The
320 * resolve bit doesn't get set properly when
321 * autoneg is off, so force it.
322 */
323 if ((phy_status & (1 << 11)) == 0) {
324 int auto_status =
325 cvmx_mdio_read(phy_addr >> 8,
326 phy_addr & 0xff, 0);
327 if ((auto_status & (1 << 12)) == 0)
328 phy_status |= 1 << 11;
329 }
330
331 /*
332 * Only return a link if the PHY has finished
333 * auto negotiation and set the resolved bit
334 * (bit 11)
335 */
336 if (phy_status & (1 << 11)) {
337 result.s.link_up = 1;
338 result.s.full_duplex = ((phy_status >> 13) & 1);
339 switch ((phy_status >> 14) & 3) {
340 case 0: /* 10 Mbps */
341 result.s.speed = 10;
342 break;
343 case 1: /* 100 Mbps */
344 result.s.speed = 100;
345 break;
346 case 2: /* 1 Gbps */
347 result.s.speed = 1000;
348 break;
349 case 3: /* Illegal */
350 result.u64 = 0;
351 break;
352 }
353 }
354 }
355 } else if (OCTEON_IS_MODEL(OCTEON_CN3XXX)
356 || OCTEON_IS_MODEL(OCTEON_CN58XX)
357 || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
358 /*
359 * We don't have a PHY address, so attempt to use
360 * in-band status. It is really important that boards
361 * not supporting in-band status never get
362 * here. Reading broken in-band status tends to do bad
363 * things
364 */
365 union cvmx_gmxx_rxx_rx_inbnd inband_status;
366 int interface = cvmx_helper_get_interface_num(ipd_port);
367 int index = cvmx_helper_get_interface_index_num(ipd_port);
368 inband_status.u64 =
369 cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
370
371 result.s.link_up = inband_status.s.status;
372 result.s.full_duplex = inband_status.s.duplex;
373 switch (inband_status.s.speed) {
374 case 0: /* 10 Mbps */
375 result.s.speed = 10;
376 break;
377 case 1: /* 100 Mbps */
378 result.s.speed = 100;
379 break;
380 case 2: /* 1 Gbps */
381 result.s.speed = 1000;
382 break;
383 case 3: /* Illegal */
384 result.u64 = 0;
385 break;
386 }
387 } else {
388 /*
389 * We don't have a PHY address and we don't have
390 * in-band status. There is no way to determine the
391 * link speed. Return down assuming this port isn't
392 * wired
393 */
394 result.u64 = 0;
395 }
396
397 /* If link is down, return all fields as zero. */
398 if (!result.s.link_up)
399 result.u64 = 0;
400
401 return result;
402}
403
404/**
405 * This function as a board specific method of changing the PHY
406 * speed, duplex, and auto-negotiation. This programs the PHY and
407 * not Octeon. This can be used to force Octeon's links to
408 * specific settings.
409 *
410 * @phy_addr: The address of the PHY to program
411 * @enable_autoneg:
412 * Non zero if you want to enable auto-negotiation.
413 * @link_info: Link speed to program. If the speed is zero and auto-negotiation
414 * is enabled, all possible negotiation speeds are advertised.
415 *
416 * Returns Zero on success, negative on failure
417 */
418int cvmx_helper_board_link_set_phy(int phy_addr,
419 cvmx_helper_board_set_phy_link_flags_types_t
420 link_flags,
421 cvmx_helper_link_info_t link_info)
422{
423
424 /* Set the flow control settings based on link_flags */
425 if ((link_flags & set_phy_link_flags_flow_control_mask) !=
426 set_phy_link_flags_flow_control_dont_touch) {
427 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
428 reg_autoneg_adver.u16 =
429 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
430 CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
431 reg_autoneg_adver.s.asymmetric_pause =
432 (link_flags & set_phy_link_flags_flow_control_mask) ==
433 set_phy_link_flags_flow_control_enable;
434 reg_autoneg_adver.s.pause =
435 (link_flags & set_phy_link_flags_flow_control_mask) ==
436 set_phy_link_flags_flow_control_enable;
437 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
438 CVMX_MDIO_PHY_REG_AUTONEG_ADVER,
439 reg_autoneg_adver.u16);
440 }
441
442 /* If speed isn't set and autoneg is on advertise all supported modes */
443 if ((link_flags & set_phy_link_flags_autoneg)
444 && (link_info.s.speed == 0)) {
445 cvmx_mdio_phy_reg_control_t reg_control;
446 cvmx_mdio_phy_reg_status_t reg_status;
447 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
448 cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
449 cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
450
451 reg_status.u16 =
452 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
453 CVMX_MDIO_PHY_REG_STATUS);
454 reg_autoneg_adver.u16 =
455 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
456 CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
457 reg_autoneg_adver.s.advert_100base_t4 =
458 reg_status.s.capable_100base_t4;
459 reg_autoneg_adver.s.advert_10base_tx_full =
460 reg_status.s.capable_10_full;
461 reg_autoneg_adver.s.advert_10base_tx_half =
462 reg_status.s.capable_10_half;
463 reg_autoneg_adver.s.advert_100base_tx_full =
464 reg_status.s.capable_100base_x_full;
465 reg_autoneg_adver.s.advert_100base_tx_half =
466 reg_status.s.capable_100base_x_half;
467 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
468 CVMX_MDIO_PHY_REG_AUTONEG_ADVER,
469 reg_autoneg_adver.u16);
470 if (reg_status.s.capable_extended_status) {
471 reg_extended_status.u16 =
472 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
473 CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
474 reg_control_1000.u16 =
475 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
476 CVMX_MDIO_PHY_REG_CONTROL_1000);
477 reg_control_1000.s.advert_1000base_t_full =
478 reg_extended_status.s.capable_1000base_t_full;
479 reg_control_1000.s.advert_1000base_t_half =
480 reg_extended_status.s.capable_1000base_t_half;
481 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
482 CVMX_MDIO_PHY_REG_CONTROL_1000,
483 reg_control_1000.u16);
484 }
485 reg_control.u16 =
486 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
487 CVMX_MDIO_PHY_REG_CONTROL);
488 reg_control.s.autoneg_enable = 1;
489 reg_control.s.restart_autoneg = 1;
490 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
491 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
492 } else if ((link_flags & set_phy_link_flags_autoneg)) {
493 cvmx_mdio_phy_reg_control_t reg_control;
494 cvmx_mdio_phy_reg_status_t reg_status;
495 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
496 cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
497
498 reg_status.u16 =
499 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
500 CVMX_MDIO_PHY_REG_STATUS);
501 reg_autoneg_adver.u16 =
502 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
503 CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
504 reg_autoneg_adver.s.advert_100base_t4 = 0;
505 reg_autoneg_adver.s.advert_10base_tx_full = 0;
506 reg_autoneg_adver.s.advert_10base_tx_half = 0;
507 reg_autoneg_adver.s.advert_100base_tx_full = 0;
508 reg_autoneg_adver.s.advert_100base_tx_half = 0;
509 if (reg_status.s.capable_extended_status) {
510 reg_control_1000.u16 =
511 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
512 CVMX_MDIO_PHY_REG_CONTROL_1000);
513 reg_control_1000.s.advert_1000base_t_full = 0;
514 reg_control_1000.s.advert_1000base_t_half = 0;
515 }
516 switch (link_info.s.speed) {
517 case 10:
518 reg_autoneg_adver.s.advert_10base_tx_full =
519 link_info.s.full_duplex;
520 reg_autoneg_adver.s.advert_10base_tx_half =
521 !link_info.s.full_duplex;
522 break;
523 case 100:
524 reg_autoneg_adver.s.advert_100base_tx_full =
525 link_info.s.full_duplex;
526 reg_autoneg_adver.s.advert_100base_tx_half =
527 !link_info.s.full_duplex;
528 break;
529 case 1000:
530 reg_control_1000.s.advert_1000base_t_full =
531 link_info.s.full_duplex;
532 reg_control_1000.s.advert_1000base_t_half =
533 !link_info.s.full_duplex;
534 break;
535 }
536 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
537 CVMX_MDIO_PHY_REG_AUTONEG_ADVER,
538 reg_autoneg_adver.u16);
539 if (reg_status.s.capable_extended_status)
540 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
541 CVMX_MDIO_PHY_REG_CONTROL_1000,
542 reg_control_1000.u16);
543 reg_control.u16 =
544 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
545 CVMX_MDIO_PHY_REG_CONTROL);
546 reg_control.s.autoneg_enable = 1;
547 reg_control.s.restart_autoneg = 1;
548 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
549 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
550 } else {
551 cvmx_mdio_phy_reg_control_t reg_control;
552 reg_control.u16 =
553 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
554 CVMX_MDIO_PHY_REG_CONTROL);
555 reg_control.s.autoneg_enable = 0;
556 reg_control.s.restart_autoneg = 1;
557 reg_control.s.duplex = link_info.s.full_duplex;
558 if (link_info.s.speed == 1000) {
559 reg_control.s.speed_msb = 1;
560 reg_control.s.speed_lsb = 0;
561 } else if (link_info.s.speed == 100) {
562 reg_control.s.speed_msb = 0;
563 reg_control.s.speed_lsb = 1;
564 } else if (link_info.s.speed == 10) {
565 reg_control.s.speed_msb = 0;
566 reg_control.s.speed_lsb = 0;
567 }
568 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
569 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
570 }
571 return 0;
572}
573
574/**
575 * This function is called by cvmx_helper_interface_probe() after it
576 * determines the number of ports Octeon can support on a specific
577 * interface. This function is the per board location to override
578 * this value. It is called with the number of ports Octeon might
579 * support and should return the number of actual ports on the
580 * board.
581 *
582 * This function must be modifed for every new Octeon board.
583 * Internally it uses switch statements based on the cvmx_sysinfo
584 * data to determine board types and revisions. It relys on the
585 * fact that every Octeon board receives a unique board type
586 * enumeration from the bootloader.
587 *
588 * @interface: Interface to probe
589 * @supported_ports:
590 * Number of ports Octeon supports.
591 *
592 * Returns Number of ports the actual board supports. Many times this will
593 * simple be "support_ports".
594 */
595int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
596{
597 switch (cvmx_sysinfo_get()->board_type) {
598 case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
599 if (interface == 0)
600 return 2;
601 break;
602 case CVMX_BOARD_TYPE_BBGW_REF:
603 if (interface == 0)
604 return 2;
605 break;
606 case CVMX_BOARD_TYPE_NIC_XLE_4G:
607 if (interface == 0)
608 return 0;
609 break;
610 /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
611 which we don't support. Disable ports connected to it */
612 case CVMX_BOARD_TYPE_EBH5600:
613 if (interface == 1)
614 return 0;
615 break;
616 }
617 return supported_ports;
618}
619
620/**
621 * Enable packet input/output from the hardware. This function is
622 * called after by cvmx_helper_packet_hardware_enable() to
623 * perform board specific initialization. For most boards
624 * nothing is needed.
625 *
626 * @interface: Interface to enable
627 *
628 * Returns Zero on success, negative on failure
629 */
630int __cvmx_helper_board_hardware_enable(int interface)
631{
632 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) {
633 if (interface == 0) {
634 /* Different config for switch port */
635 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
636 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
637 /*
638 * Boards with gigabit WAN ports need a
639 * different setting that is compatible with
640 * 100 Mbit settings
641 */
642 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface),
643 0xc);
644 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface),
645 0xc);
646 }
647 } else if (cvmx_sysinfo_get()->board_type ==
648 CVMX_BOARD_TYPE_CN3010_EVB_HS5) {
649 /*
650 * Broadcom PHYs require differnet ASX
651 * clocks. Unfortunately many boards don't define a
652 * new board Id and simply mangle the
653 * CN3010_EVB_HS5
654 */
655 if (interface == 0) {
656 /*
657 * Some boards use a hacked up bootloader that
658 * identifies them as CN3010_EVB_HS5
659 * evaluation boards. This leads to all kinds
660 * of configuration problems. Detect one
661 * case, and print warning, while trying to do
662 * the right thing.
663 */
664 int phy_addr = cvmx_helper_board_get_mii_address(0);
665 if (phy_addr != -1) {
666 int phy_identifier =
667 cvmx_mdio_read(phy_addr >> 8,
668 phy_addr & 0xff, 0x2);
669 /* Is it a Broadcom PHY? */
670 if (phy_identifier == 0x0143) {
671 cvmx_dprintf("\n");
672 cvmx_dprintf("ERROR:\n");
673 cvmx_dprintf
674 ("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
675 cvmx_dprintf
676 ("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
677 cvmx_dprintf
678 ("ERROR: All boards require a unique board type to identify them.\n");
679 cvmx_dprintf("ERROR:\n");
680 cvmx_dprintf("\n");
681 cvmx_wait(1000000000);
682 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX
683 (0, interface), 5);
684 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX
685 (0, interface), 5);
686 }
687 }
688 }
689 }
690 return 0;
691}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c
new file mode 100644
index 000000000000..c239e5f4ab9a
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-fpa.c
@@ -0,0 +1,243 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/**
29 * @file
30 *
31 * Helper functions for FPA setup.
32 *
33 */
34#include "executive-config.h"
35#include "cvmx-config.h"
36#include "cvmx.h"
37#include "cvmx-bootmem.h"
38#include "cvmx-fpa.h"
39#include "cvmx-helper-fpa.h"
40
41/**
42 * Allocate memory for and initialize a single FPA pool.
43 *
44 * @pool: Pool to initialize
45 * @buffer_size: Size of buffers to allocate in bytes
46 * @buffers: Number of buffers to put in the pool. Zero is allowed
47 * @name: String name of the pool for debugging purposes
48 * Returns Zero on success, non-zero on failure
49 */
50static int __cvmx_helper_initialize_fpa_pool(int pool, uint64_t buffer_size,
51 uint64_t buffers, const char *name)
52{
53 uint64_t current_num;
54 void *memory;
55 uint64_t align = CVMX_CACHE_LINE_SIZE;
56
57 /*
58 * Align the allocation so that power of 2 size buffers are
59 * naturally aligned.
60 */
61 while (align < buffer_size)
62 align = align << 1;
63
64 if (buffers == 0)
65 return 0;
66
67 current_num = cvmx_read_csr(CVMX_FPA_QUEX_AVAILABLE(pool));
68 if (current_num) {
69 cvmx_dprintf("Fpa pool %d(%s) already has %llu buffers. "
70 "Skipping setup.\n",
71 pool, name, (unsigned long long)current_num);
72 return 0;
73 }
74
75 memory = cvmx_bootmem_alloc(buffer_size * buffers, align);
76 if (memory == NULL) {
77 cvmx_dprintf("Out of memory initializing fpa pool %d(%s).\n",
78 pool, name);
79 return -1;
80 }
81 cvmx_fpa_setup_pool(pool, name, memory, buffer_size, buffers);
82 return 0;
83}
84
85/**
86 * Allocate memory and initialize the FPA pools using memory
87 * from cvmx-bootmem. Specifying zero for the number of
88 * buffers will cause that FPA pool to not be setup. This is
89 * useful if you aren't using some of the hardware and want
90 * to save memory. Use cvmx_helper_initialize_fpa instead of
91 * this function directly.
92 *
93 * @pip_pool: Should always be CVMX_FPA_PACKET_POOL
94 * @pip_size: Should always be CVMX_FPA_PACKET_POOL_SIZE
95 * @pip_buffers:
96 * Number of packet buffers.
97 * @wqe_pool: Should always be CVMX_FPA_WQE_POOL
98 * @wqe_size: Should always be CVMX_FPA_WQE_POOL_SIZE
99 * @wqe_entries:
100 * Number of work queue entries
101 * @pko_pool: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL
102 * @pko_size: Should always be CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE
103 * @pko_buffers:
104 * PKO Command buffers. You should at minimum have two per
105 * each PKO queue.
106 * @tim_pool: Should always be CVMX_FPA_TIMER_POOL
107 * @tim_size: Should always be CVMX_FPA_TIMER_POOL_SIZE
108 * @tim_buffers:
109 * TIM ring buffer command queues. At least two per timer bucket
110 * is recommened.
111 * @dfa_pool: Should always be CVMX_FPA_DFA_POOL
112 * @dfa_size: Should always be CVMX_FPA_DFA_POOL_SIZE
113 * @dfa_buffers:
114 * DFA command buffer. A relatively small (32 for example)
115 * number should work.
116 * Returns Zero on success, non-zero if out of memory
117 */
118static int __cvmx_helper_initialize_fpa(int pip_pool, int pip_size,
119 int pip_buffers, int wqe_pool,
120 int wqe_size, int wqe_entries,
121 int pko_pool, int pko_size,
122 int pko_buffers, int tim_pool,
123 int tim_size, int tim_buffers,
124 int dfa_pool, int dfa_size,
125 int dfa_buffers)
126{
127 int status;
128
129 cvmx_fpa_enable();
130
131 if ((pip_buffers > 0) && (pip_buffers <= 64))
132 cvmx_dprintf
133 ("Warning: %d packet buffers may not be enough for hardware"
134 " prefetch. 65 or more is recommended.\n", pip_buffers);
135
136 if (pip_pool >= 0) {
137 status =
138 __cvmx_helper_initialize_fpa_pool(pip_pool, pip_size,
139 pip_buffers,
140 "Packet Buffers");
141 if (status)
142 return status;
143 }
144
145 if (wqe_pool >= 0) {
146 status =
147 __cvmx_helper_initialize_fpa_pool(wqe_pool, wqe_size,
148 wqe_entries,
149 "Work Queue Entries");
150 if (status)
151 return status;
152 }
153
154 if (pko_pool >= 0) {
155 status =
156 __cvmx_helper_initialize_fpa_pool(pko_pool, pko_size,
157 pko_buffers,
158 "PKO Command Buffers");
159 if (status)
160 return status;
161 }
162
163 if (tim_pool >= 0) {
164 status =
165 __cvmx_helper_initialize_fpa_pool(tim_pool, tim_size,
166 tim_buffers,
167 "TIM Command Buffers");
168 if (status)
169 return status;
170 }
171
172 if (dfa_pool >= 0) {
173 status =
174 __cvmx_helper_initialize_fpa_pool(dfa_pool, dfa_size,
175 dfa_buffers,
176 "DFA Command Buffers");
177 if (status)
178 return status;
179 }
180
181 return 0;
182}
183
184/**
185 * Allocate memory and initialize the FPA pools using memory
186 * from cvmx-bootmem. Sizes of each element in the pools is
187 * controlled by the cvmx-config.h header file. Specifying
188 * zero for any parameter will cause that FPA pool to not be
189 * setup. This is useful if you aren't using some of the
190 * hardware and want to save memory.
191 *
192 * @packet_buffers:
193 * Number of packet buffers to allocate
194 * @work_queue_entries:
195 * Number of work queue entries
196 * @pko_buffers:
197 * PKO Command buffers. You should at minimum have two per
198 * each PKO queue.
199 * @tim_buffers:
200 * TIM ring buffer command queues. At least two per timer bucket
201 * is recommened.
202 * @dfa_buffers:
203 * DFA command buffer. A relatively small (32 for example)
204 * number should work.
205 * Returns Zero on success, non-zero if out of memory
206 */
207int cvmx_helper_initialize_fpa(int packet_buffers, int work_queue_entries,
208 int pko_buffers, int tim_buffers,
209 int dfa_buffers)
210{
211#ifndef CVMX_FPA_PACKET_POOL
212#define CVMX_FPA_PACKET_POOL -1
213#define CVMX_FPA_PACKET_POOL_SIZE 0
214#endif
215#ifndef CVMX_FPA_WQE_POOL
216#define CVMX_FPA_WQE_POOL -1
217#define CVMX_FPA_WQE_POOL_SIZE 0
218#endif
219#ifndef CVMX_FPA_OUTPUT_BUFFER_POOL
220#define CVMX_FPA_OUTPUT_BUFFER_POOL -1
221#define CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE 0
222#endif
223#ifndef CVMX_FPA_TIMER_POOL
224#define CVMX_FPA_TIMER_POOL -1
225#define CVMX_FPA_TIMER_POOL_SIZE 0
226#endif
227#ifndef CVMX_FPA_DFA_POOL
228#define CVMX_FPA_DFA_POOL -1
229#define CVMX_FPA_DFA_POOL_SIZE 0
230#endif
231 return __cvmx_helper_initialize_fpa(CVMX_FPA_PACKET_POOL,
232 CVMX_FPA_PACKET_POOL_SIZE,
233 packet_buffers, CVMX_FPA_WQE_POOL,
234 CVMX_FPA_WQE_POOL_SIZE,
235 work_queue_entries,
236 CVMX_FPA_OUTPUT_BUFFER_POOL,
237 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE,
238 pko_buffers, CVMX_FPA_TIMER_POOL,
239 CVMX_FPA_TIMER_POOL_SIZE,
240 tim_buffers, CVMX_FPA_DFA_POOL,
241 CVMX_FPA_DFA_POOL_SIZE,
242 dfa_buffers);
243}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-loop.c b/arch/mips/cavium-octeon/executive/cvmx-helper-loop.c
new file mode 100644
index 000000000000..bfbd46115e71
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-loop.c
@@ -0,0 +1,85 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Functions for LOOP initialization, configuration,
30 * and monitoring.
31 */
32#include <asm/octeon/octeon.h>
33
34#include <asm/octeon/cvmx-config.h>
35
36#include <asm/octeon/cvmx-helper.h>
37#include <asm/octeon/cvmx-pip-defs.h>
38
39/**
40 * Probe a LOOP interface and determine the number of ports
41 * connected to it. The LOOP interface should still be down
42 * after this call.
43 *
44 * @interface: Interface to probe
45 *
46 * Returns Number of ports on the interface. Zero to disable.
47 */
48int __cvmx_helper_loop_probe(int interface)
49{
50 union cvmx_ipd_sub_port_fcs ipd_sub_port_fcs;
51 int num_ports = 4;
52 int port;
53
54 /* We need to disable length checking so packet < 64 bytes and jumbo
55 frames don't get errors */
56 for (port = 0; port < num_ports; port++) {
57 union cvmx_pip_prt_cfgx port_cfg;
58 int ipd_port = cvmx_helper_get_ipd_port(interface, port);
59 port_cfg.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
60 port_cfg.s.maxerr_en = 0;
61 port_cfg.s.minerr_en = 0;
62 cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_cfg.u64);
63 }
64
65 /* Disable FCS stripping for loopback ports */
66 ipd_sub_port_fcs.u64 = cvmx_read_csr(CVMX_IPD_SUB_PORT_FCS);
67 ipd_sub_port_fcs.s.port_bit2 = 0;
68 cvmx_write_csr(CVMX_IPD_SUB_PORT_FCS, ipd_sub_port_fcs.u64);
69 return num_ports;
70}
71
72/**
73 * Bringup and enable a LOOP interface. After this call packet
74 * I/O should be fully functional. This is called with IPD
75 * enabled but PKO disabled.
76 *
77 * @interface: Interface to bring up
78 *
79 * Returns Zero on success, negative on failure
80 */
81int __cvmx_helper_loop_enable(int interface)
82{
83 /* Do nothing. */
84 return 0;
85}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-npi.c b/arch/mips/cavium-octeon/executive/cvmx-helper-npi.c
new file mode 100644
index 000000000000..cc94cfa545b4
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-npi.c
@@ -0,0 +1,113 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Functions for NPI initialization, configuration,
30 * and monitoring.
31 */
32#include <asm/octeon/octeon.h>
33
34#include <asm/octeon/cvmx-config.h>
35
36#include <asm/octeon/cvmx-helper.h>
37
38#include <asm/octeon/cvmx-pip-defs.h>
39
40/**
41 * Probe a NPI interface and determine the number of ports
42 * connected to it. The NPI interface should still be down
43 * after this call.
44 *
45 * @interface: Interface to probe
46 *
47 * Returns Number of ports on the interface. Zero to disable.
48 */
49int __cvmx_helper_npi_probe(int interface)
50{
51#if CVMX_PKO_QUEUES_PER_PORT_PCI > 0
52 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
53 return 4;
54 else if (OCTEON_IS_MODEL(OCTEON_CN56XX)
55 && !OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X))
56 /* The packet engines didn't exist before pass 2 */
57 return 4;
58 else if (OCTEON_IS_MODEL(OCTEON_CN52XX)
59 && !OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X))
60 /* The packet engines didn't exist before pass 2 */
61 return 4;
62#if 0
63 /*
64 * Technically CN30XX, CN31XX, and CN50XX contain packet
65 * engines, but nobody ever uses them. Since this is the case,
66 * we disable them here.
67 */
68 else if (OCTEON_IS_MODEL(OCTEON_CN31XX)
69 || OCTEON_IS_MODEL(OCTEON_CN50XX))
70 return 2;
71 else if (OCTEON_IS_MODEL(OCTEON_CN30XX))
72 return 1;
73#endif
74#endif
75 return 0;
76}
77
78/**
79 * Bringup and enable a NPI interface. After this call packet
80 * I/O should be fully functional. This is called with IPD
81 * enabled but PKO disabled.
82 *
83 * @interface: Interface to bring up
84 *
85 * Returns Zero on success, negative on failure
86 */
87int __cvmx_helper_npi_enable(int interface)
88{
89 /*
90 * On CN50XX, CN52XX, and CN56XX we need to disable length
91 * checking so packet < 64 bytes and jumbo frames don't get
92 * errors.
93 */
94 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) &&
95 !OCTEON_IS_MODEL(OCTEON_CN58XX)) {
96 int num_ports = cvmx_helper_ports_on_interface(interface);
97 int port;
98 for (port = 0; port < num_ports; port++) {
99 union cvmx_pip_prt_cfgx port_cfg;
100 int ipd_port =
101 cvmx_helper_get_ipd_port(interface, port);
102 port_cfg.u64 =
103 cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
104 port_cfg.s.maxerr_en = 0;
105 port_cfg.s.minerr_en = 0;
106 cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port),
107 port_cfg.u64);
108 }
109 }
110
111 /* Enables are controlled by the remote host, so nothing to do here */
112 return 0;
113}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c
new file mode 100644
index 000000000000..82b21843421c
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-rgmii.c
@@ -0,0 +1,526 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Functions for RGMII/GMII/MII initialization, configuration,
30 * and monitoring.
31 */
32#include <asm/octeon/octeon.h>
33
34#include <asm/octeon/cvmx-config.h>
35
36
37#include <asm/octeon/cvmx-mdio.h>
38#include <asm/octeon/cvmx-pko.h>
39#include <asm/octeon/cvmx-helper.h>
40#include <asm/octeon/cvmx-helper-board.h>
41
42#include <asm/octeon/cvmx-npi-defs.h>
43#include <asm/octeon/cvmx-gmxx-defs.h>
44#include <asm/octeon/cvmx-asxx-defs.h>
45#include <asm/octeon/cvmx-dbg-defs.h>
46
47void __cvmx_interrupt_gmxx_enable(int interface);
48void __cvmx_interrupt_asxx_enable(int block);
49
50/**
51 * Probe RGMII ports and determine the number present
52 *
53 * @interface: Interface to probe
54 *
55 * Returns Number of RGMII/GMII/MII ports (0-4).
56 */
57int __cvmx_helper_rgmii_probe(int interface)
58{
59 int num_ports = 0;
60 union cvmx_gmxx_inf_mode mode;
61 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
62
63 if (mode.s.type) {
64 if (OCTEON_IS_MODEL(OCTEON_CN38XX)
65 || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
66 cvmx_dprintf("ERROR: RGMII initialize called in "
67 "SPI interface\n");
68 } else if (OCTEON_IS_MODEL(OCTEON_CN31XX)
69 || OCTEON_IS_MODEL(OCTEON_CN30XX)
70 || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
71 /*
72 * On these chips "type" says we're in
73 * GMII/MII mode. This limits us to 2 ports
74 */
75 num_ports = 2;
76 } else {
77 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n",
78 __func__);
79 }
80 } else {
81 if (OCTEON_IS_MODEL(OCTEON_CN38XX)
82 || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
83 num_ports = 4;
84 } else if (OCTEON_IS_MODEL(OCTEON_CN31XX)
85 || OCTEON_IS_MODEL(OCTEON_CN30XX)
86 || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
87 num_ports = 3;
88 } else {
89 cvmx_dprintf("ERROR: Unsupported Octeon model in %s\n",
90 __func__);
91 }
92 }
93 return num_ports;
94}
95
96/**
97 * Put an RGMII interface in loopback mode. Internal packets sent
98 * out will be received back again on the same port. Externally
99 * received packets will echo back out.
100 *
101 * @port: IPD port number to loop.
102 */
103void cvmx_helper_rgmii_internal_loopback(int port)
104{
105 int interface = (port >> 4) & 1;
106 int index = port & 0xf;
107 uint64_t tmp;
108
109 union cvmx_gmxx_prtx_cfg gmx_cfg;
110 gmx_cfg.u64 = 0;
111 gmx_cfg.s.duplex = 1;
112 gmx_cfg.s.slottime = 1;
113 gmx_cfg.s.speed = 1;
114 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
115 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
116 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
117 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
118 tmp = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
119 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), (1 << index) | tmp);
120 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
121 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), (1 << index) | tmp);
122 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
123 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), (1 << index) | tmp);
124 gmx_cfg.s.en = 1;
125 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
126}
127
128/**
129 * Workaround ASX setup errata with CN38XX pass1
130 *
131 * @interface: Interface to setup
132 * @port: Port to setup (0..3)
133 * @cpu_clock_hz:
134 * Chip frequency in Hertz
135 *
136 * Returns Zero on success, negative on failure
137 */
138static int __cvmx_helper_errata_asx_pass1(int interface, int port,
139 int cpu_clock_hz)
140{
141 /* Set hi water mark as per errata GMX-4 */
142 if (cpu_clock_hz >= 325000000 && cpu_clock_hz < 375000000)
143 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 12);
144 else if (cpu_clock_hz >= 375000000 && cpu_clock_hz < 437000000)
145 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 11);
146 else if (cpu_clock_hz >= 437000000 && cpu_clock_hz < 550000000)
147 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 10);
148 else if (cpu_clock_hz >= 550000000 && cpu_clock_hz < 687000000)
149 cvmx_write_csr(CVMX_ASXX_TX_HI_WATERX(port, interface), 9);
150 else
151 cvmx_dprintf("Illegal clock frequency (%d). "
152 "CVMX_ASXX_TX_HI_WATERX not set\n", cpu_clock_hz);
153 return 0;
154}
155
156/**
157 * Configure all of the ASX, GMX, and PKO regsiters required
158 * to get RGMII to function on the supplied interface.
159 *
160 * @interface: PKO Interface to configure (0 or 1)
161 *
162 * Returns Zero on success
163 */
164int __cvmx_helper_rgmii_enable(int interface)
165{
166 int num_ports = cvmx_helper_ports_on_interface(interface);
167 int port;
168 struct cvmx_sysinfo *sys_info_ptr = cvmx_sysinfo_get();
169 union cvmx_gmxx_inf_mode mode;
170 union cvmx_asxx_tx_prt_en asx_tx;
171 union cvmx_asxx_rx_prt_en asx_rx;
172
173 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
174
175 if (mode.s.en == 0)
176 return -1;
177 if ((OCTEON_IS_MODEL(OCTEON_CN38XX) ||
178 OCTEON_IS_MODEL(OCTEON_CN58XX)) && mode.s.type == 1)
179 /* Ignore SPI interfaces */
180 return -1;
181
182 /* Configure the ASX registers needed to use the RGMII ports */
183 asx_tx.u64 = 0;
184 asx_tx.s.prt_en = cvmx_build_mask(num_ports);
185 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface), asx_tx.u64);
186
187 asx_rx.u64 = 0;
188 asx_rx.s.prt_en = cvmx_build_mask(num_ports);
189 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface), asx_rx.u64);
190
191 /* Configure the GMX registers needed to use the RGMII ports */
192 for (port = 0; port < num_ports; port++) {
193 /* Setting of CVMX_GMXX_TXX_THRESH has been moved to
194 __cvmx_helper_setup_gmx() */
195
196 if (cvmx_octeon_is_pass1())
197 __cvmx_helper_errata_asx_pass1(interface, port,
198 sys_info_ptr->
199 cpu_clock_hz);
200 else {
201 /*
202 * Configure more flexible RGMII preamble
203 * checking. Pass 1 doesn't support this
204 * feature.
205 */
206 union cvmx_gmxx_rxx_frm_ctl frm_ctl;
207 frm_ctl.u64 =
208 cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL
209 (port, interface));
210 /* New field, so must be compile time */
211 frm_ctl.s.pre_free = 1;
212 cvmx_write_csr(CVMX_GMXX_RXX_FRM_CTL(port, interface),
213 frm_ctl.u64);
214 }
215
216 /*
217 * Each pause frame transmitted will ask for about 10M
218 * bit times before resume. If buffer space comes
219 * available before that time has expired, an XON
220 * pause frame (0 time) will be transmitted to restart
221 * the flow.
222 */
223 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_TIME(port, interface),
224 20000);
225 cvmx_write_csr(CVMX_GMXX_TXX_PAUSE_PKT_INTERVAL
226 (port, interface), 19000);
227
228 if (OCTEON_IS_MODEL(OCTEON_CN50XX)) {
229 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface),
230 16);
231 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface),
232 16);
233 } else {
234 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(port, interface),
235 24);
236 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(port, interface),
237 24);
238 }
239 }
240
241 __cvmx_helper_setup_gmx(interface, num_ports);
242
243 /* enable the ports now */
244 for (port = 0; port < num_ports; port++) {
245 union cvmx_gmxx_prtx_cfg gmx_cfg;
246 cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port
247 (interface, port));
248 gmx_cfg.u64 =
249 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(port, interface));
250 gmx_cfg.s.en = 1;
251 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(port, interface),
252 gmx_cfg.u64);
253 }
254 __cvmx_interrupt_asxx_enable(interface);
255 __cvmx_interrupt_gmxx_enable(interface);
256
257 return 0;
258}
259
260/**
261 * Return the link state of an IPD/PKO port as returned by
262 * auto negotiation. The result of this function may not match
263 * Octeon's link config if auto negotiation has changed since
264 * the last call to cvmx_helper_link_set().
265 *
266 * @ipd_port: IPD/PKO port to query
267 *
268 * Returns Link state
269 */
270cvmx_helper_link_info_t __cvmx_helper_rgmii_link_get(int ipd_port)
271{
272 int interface = cvmx_helper_get_interface_num(ipd_port);
273 int index = cvmx_helper_get_interface_index_num(ipd_port);
274 union cvmx_asxx_prt_loop asxx_prt_loop;
275
276 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
277 if (asxx_prt_loop.s.int_loop & (1 << index)) {
278 /* Force 1Gbps full duplex on internal loopback */
279 cvmx_helper_link_info_t result;
280 result.u64 = 0;
281 result.s.full_duplex = 1;
282 result.s.link_up = 1;
283 result.s.speed = 1000;
284 return result;
285 } else
286 return __cvmx_helper_board_link_get(ipd_port);
287}
288
289/**
290 * Configure an IPD/PKO port for the specified link state. This
291 * function does not influence auto negotiation at the PHY level.
292 * The passed link state must always match the link state returned
293 * by cvmx_helper_link_get(). It is normally best to use
294 * cvmx_helper_link_autoconf() instead.
295 *
296 * @ipd_port: IPD/PKO port to configure
297 * @link_info: The new link state
298 *
299 * Returns Zero on success, negative on failure
300 */
301int __cvmx_helper_rgmii_link_set(int ipd_port,
302 cvmx_helper_link_info_t link_info)
303{
304 int result = 0;
305 int interface = cvmx_helper_get_interface_num(ipd_port);
306 int index = cvmx_helper_get_interface_index_num(ipd_port);
307 union cvmx_gmxx_prtx_cfg original_gmx_cfg;
308 union cvmx_gmxx_prtx_cfg new_gmx_cfg;
309 union cvmx_pko_mem_queue_qos pko_mem_queue_qos;
310 union cvmx_pko_mem_queue_qos pko_mem_queue_qos_save[16];
311 union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp;
312 union cvmx_gmxx_tx_ovr_bp gmx_tx_ovr_bp_save;
313 int i;
314
315 /* Ignore speed sets in the simulator */
316 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM)
317 return 0;
318
319 /* Read the current settings so we know the current enable state */
320 original_gmx_cfg.u64 =
321 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
322 new_gmx_cfg = original_gmx_cfg;
323
324 /* Disable the lowest level RX */
325 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
326 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) &
327 ~(1 << index));
328
329 memset(pko_mem_queue_qos_save, 0, sizeof(pko_mem_queue_qos_save));
330 /* Disable all queues so that TX should become idle */
331 for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) {
332 int queue = cvmx_pko_get_base_queue(ipd_port) + i;
333 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
334 pko_mem_queue_qos.u64 = cvmx_read_csr(CVMX_PKO_MEM_QUEUE_QOS);
335 pko_mem_queue_qos.s.pid = ipd_port;
336 pko_mem_queue_qos.s.qid = queue;
337 pko_mem_queue_qos_save[i] = pko_mem_queue_qos;
338 pko_mem_queue_qos.s.qos_mask = 0;
339 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS, pko_mem_queue_qos.u64);
340 }
341
342 /* Disable backpressure */
343 gmx_tx_ovr_bp.u64 = cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
344 gmx_tx_ovr_bp_save = gmx_tx_ovr_bp;
345 gmx_tx_ovr_bp.s.bp &= ~(1 << index);
346 gmx_tx_ovr_bp.s.en |= 1 << index;
347 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp.u64);
348 cvmx_read_csr(CVMX_GMXX_TX_OVR_BP(interface));
349
350 /*
351 * Poll the GMX state machine waiting for it to become
352 * idle. Preferably we should only change speed when it is
353 * idle. If it doesn't become idle we will still do the speed
354 * change, but there is a slight chance that GMX will
355 * lockup.
356 */
357 cvmx_write_csr(CVMX_NPI_DBG_SELECT,
358 interface * 0x800 + index * 0x100 + 0x880);
359 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 7,
360 ==, 0, 10000);
361 CVMX_WAIT_FOR_FIELD64(CVMX_DBG_DATA, union cvmx_dbg_data, data & 0xf,
362 ==, 0, 10000);
363
364 /* Disable the port before we make any changes */
365 new_gmx_cfg.s.en = 0;
366 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
367 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
368
369 /* Set full/half duplex */
370 if (cvmx_octeon_is_pass1())
371 /* Half duplex is broken for 38XX Pass 1 */
372 new_gmx_cfg.s.duplex = 1;
373 else if (!link_info.s.link_up)
374 /* Force full duplex on down links */
375 new_gmx_cfg.s.duplex = 1;
376 else
377 new_gmx_cfg.s.duplex = link_info.s.full_duplex;
378
379 /* Set the link speed. Anything unknown is set to 1Gbps */
380 if (link_info.s.speed == 10) {
381 new_gmx_cfg.s.slottime = 0;
382 new_gmx_cfg.s.speed = 0;
383 } else if (link_info.s.speed == 100) {
384 new_gmx_cfg.s.slottime = 0;
385 new_gmx_cfg.s.speed = 0;
386 } else {
387 new_gmx_cfg.s.slottime = 1;
388 new_gmx_cfg.s.speed = 1;
389 }
390
391 /* Adjust the clocks */
392 if (link_info.s.speed == 10) {
393 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 50);
394 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
395 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
396 } else if (link_info.s.speed == 100) {
397 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 5);
398 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x40);
399 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
400 } else {
401 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
402 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
403 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
404 }
405
406 if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
407 if ((link_info.s.speed == 10) || (link_info.s.speed == 100)) {
408 union cvmx_gmxx_inf_mode mode;
409 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
410
411 /*
412 * Port .en .type .p0mii Configuration
413 * ---- --- ----- ------ -----------------------------------------
414 * X 0 X X All links are disabled.
415 * 0 1 X 0 Port 0 is RGMII
416 * 0 1 X 1 Port 0 is MII
417 * 1 1 0 X Ports 1 and 2 are configured as RGMII ports.
418 * 1 1 1 X Port 1: GMII/MII; Port 2: disabled. GMII or
419 * MII port is selected by GMX_PRT1_CFG[SPEED].
420 */
421
422 /* In MII mode, CLK_CNT = 1. */
423 if (((index == 0) && (mode.s.p0mii == 1))
424 || ((index != 0) && (mode.s.type == 1))) {
425 cvmx_write_csr(CVMX_GMXX_TXX_CLK
426 (index, interface), 1);
427 }
428 }
429 }
430
431 /* Do a read to make sure all setup stuff is complete */
432 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
433
434 /* Save the new GMX setting without enabling the port */
435 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
436
437 /* Enable the lowest level RX */
438 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
439 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface)) | (1 <<
440 index));
441
442 /* Re-enable the TX path */
443 for (i = 0; i < cvmx_pko_get_num_queues(ipd_port); i++) {
444 int queue = cvmx_pko_get_base_queue(ipd_port) + i;
445 cvmx_write_csr(CVMX_PKO_REG_READ_IDX, queue);
446 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_QOS,
447 pko_mem_queue_qos_save[i].u64);
448 }
449
450 /* Restore backpressure */
451 cvmx_write_csr(CVMX_GMXX_TX_OVR_BP(interface), gmx_tx_ovr_bp_save.u64);
452
453 /* Restore the GMX enable state. Port config is complete */
454 new_gmx_cfg.s.en = original_gmx_cfg.s.en;
455 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), new_gmx_cfg.u64);
456
457 return result;
458}
459
460/**
461 * Configure a port for internal and/or external loopback. Internal loopback
462 * causes packets sent by the port to be received by Octeon. External loopback
463 * causes packets received from the wire to sent out again.
464 *
465 * @ipd_port: IPD/PKO port to loopback.
466 * @enable_internal:
467 * Non zero if you want internal loopback
468 * @enable_external:
469 * Non zero if you want external loopback
470 *
471 * Returns Zero on success, negative on failure.
472 */
473int __cvmx_helper_rgmii_configure_loopback(int ipd_port, int enable_internal,
474 int enable_external)
475{
476 int interface = cvmx_helper_get_interface_num(ipd_port);
477 int index = cvmx_helper_get_interface_index_num(ipd_port);
478 int original_enable;
479 union cvmx_gmxx_prtx_cfg gmx_cfg;
480 union cvmx_asxx_prt_loop asxx_prt_loop;
481
482 /* Read the current enable state and save it */
483 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
484 original_enable = gmx_cfg.s.en;
485 /* Force port to be disabled */
486 gmx_cfg.s.en = 0;
487 if (enable_internal) {
488 /* Force speed if we're doing internal loopback */
489 gmx_cfg.s.duplex = 1;
490 gmx_cfg.s.slottime = 1;
491 gmx_cfg.s.speed = 1;
492 cvmx_write_csr(CVMX_GMXX_TXX_CLK(index, interface), 1);
493 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 0x200);
494 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0x2000);
495 }
496 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
497
498 /* Set the loopback bits */
499 asxx_prt_loop.u64 = cvmx_read_csr(CVMX_ASXX_PRT_LOOP(interface));
500 if (enable_internal)
501 asxx_prt_loop.s.int_loop |= 1 << index;
502 else
503 asxx_prt_loop.s.int_loop &= ~(1 << index);
504 if (enable_external)
505 asxx_prt_loop.s.ext_loop |= 1 << index;
506 else
507 asxx_prt_loop.s.ext_loop &= ~(1 << index);
508 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(interface), asxx_prt_loop.u64);
509
510 /* Force enables in internal loopback */
511 if (enable_internal) {
512 uint64_t tmp;
513 tmp = cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(interface));
514 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(interface),
515 (1 << index) | tmp);
516 tmp = cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(interface));
517 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(interface),
518 (1 << index) | tmp);
519 original_enable = 1;
520 }
521
522 /* Restore the enable state */
523 gmx_cfg.s.en = original_enable;
524 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmx_cfg.u64);
525 return 0;
526}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c
new file mode 100644
index 000000000000..464347ffd362
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c
@@ -0,0 +1,550 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Functions for SGMII initialization, configuration,
30 * and monitoring.
31 */
32
33#include <asm/octeon/octeon.h>
34
35#include <asm/octeon/cvmx-config.h>
36
37#include <asm/octeon/cvmx-mdio.h>
38#include <asm/octeon/cvmx-helper.h>
39#include <asm/octeon/cvmx-helper-board.h>
40
41#include <asm/octeon/cvmx-gmxx-defs.h>
42#include <asm/octeon/cvmx-pcsx-defs.h>
43
44void __cvmx_interrupt_gmxx_enable(int interface);
45void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block);
46void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index);
47
48/**
49 * Perform initialization required only once for an SGMII port.
50 *
51 * @interface: Interface to init
52 * @index: Index of prot on the interface
53 *
54 * Returns Zero on success, negative on failure
55 */
56static int __cvmx_helper_sgmii_hardware_init_one_time(int interface, int index)
57{
58 const uint64_t clock_mhz = cvmx_sysinfo_get()->cpu_clock_hz / 1000000;
59 union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
60 union cvmx_pcsx_linkx_timer_count_reg pcsx_linkx_timer_count_reg;
61 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
62
63 /* Disable GMX */
64 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
65 gmxx_prtx_cfg.s.en = 0;
66 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
67
68 /*
69 * Write PCS*_LINK*_TIMER_COUNT_REG[COUNT] with the
70 * appropriate value. 1000BASE-X specifies a 10ms
71 * interval. SGMII specifies a 1.6ms interval.
72 */
73 pcs_misc_ctl_reg.u64 =
74 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
75 pcsx_linkx_timer_count_reg.u64 =
76 cvmx_read_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface));
77 if (pcs_misc_ctl_reg.s.mode) {
78 /* 1000BASE-X */
79 pcsx_linkx_timer_count_reg.s.count =
80 (10000ull * clock_mhz) >> 10;
81 } else {
82 /* SGMII */
83 pcsx_linkx_timer_count_reg.s.count =
84 (1600ull * clock_mhz) >> 10;
85 }
86 cvmx_write_csr(CVMX_PCSX_LINKX_TIMER_COUNT_REG(index, interface),
87 pcsx_linkx_timer_count_reg.u64);
88
89 /*
90 * Write the advertisement register to be used as the
91 * tx_Config_Reg<D15:D0> of the autonegotiation. In
92 * 1000BASE-X mode, tx_Config_Reg<D15:D0> is PCS*_AN*_ADV_REG.
93 * In SGMII PHY mode, tx_Config_Reg<D15:D0> is
94 * PCS*_SGM*_AN_ADV_REG. In SGMII MAC mode,
95 * tx_Config_Reg<D15:D0> is the fixed value 0x4001, so this
96 * step can be skipped.
97 */
98 if (pcs_misc_ctl_reg.s.mode) {
99 /* 1000BASE-X */
100 union cvmx_pcsx_anx_adv_reg pcsx_anx_adv_reg;
101 pcsx_anx_adv_reg.u64 =
102 cvmx_read_csr(CVMX_PCSX_ANX_ADV_REG(index, interface));
103 pcsx_anx_adv_reg.s.rem_flt = 0;
104 pcsx_anx_adv_reg.s.pause = 3;
105 pcsx_anx_adv_reg.s.hfd = 1;
106 pcsx_anx_adv_reg.s.fd = 1;
107 cvmx_write_csr(CVMX_PCSX_ANX_ADV_REG(index, interface),
108 pcsx_anx_adv_reg.u64);
109 } else {
110 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
111 pcsx_miscx_ctl_reg.u64 =
112 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
113 if (pcsx_miscx_ctl_reg.s.mac_phy) {
114 /* PHY Mode */
115 union cvmx_pcsx_sgmx_an_adv_reg pcsx_sgmx_an_adv_reg;
116 pcsx_sgmx_an_adv_reg.u64 =
117 cvmx_read_csr(CVMX_PCSX_SGMX_AN_ADV_REG
118 (index, interface));
119 pcsx_sgmx_an_adv_reg.s.link = 1;
120 pcsx_sgmx_an_adv_reg.s.dup = 1;
121 pcsx_sgmx_an_adv_reg.s.speed = 2;
122 cvmx_write_csr(CVMX_PCSX_SGMX_AN_ADV_REG
123 (index, interface),
124 pcsx_sgmx_an_adv_reg.u64);
125 } else {
126 /* MAC Mode - Nothing to do */
127 }
128 }
129 return 0;
130}
131
132/**
133 * Initialize the SERTES link for the first time or after a loss
134 * of link.
135 *
136 * @interface: Interface to init
137 * @index: Index of prot on the interface
138 *
139 * Returns Zero on success, negative on failure
140 */
141static int __cvmx_helper_sgmii_hardware_init_link(int interface, int index)
142{
143 union cvmx_pcsx_mrx_control_reg control_reg;
144
145 /*
146 * Take PCS through a reset sequence.
147 * PCS*_MR*_CONTROL_REG[PWR_DN] should be cleared to zero.
148 * Write PCS*_MR*_CONTROL_REG[RESET]=1 (while not changing the
149 * value of the other PCS*_MR*_CONTROL_REG bits). Read
150 * PCS*_MR*_CONTROL_REG[RESET] until it changes value to
151 * zero.
152 */
153 control_reg.u64 =
154 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
155 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
156 control_reg.s.reset = 1;
157 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
158 control_reg.u64);
159 if (CVMX_WAIT_FOR_FIELD64
160 (CVMX_PCSX_MRX_CONTROL_REG(index, interface),
161 union cvmx_pcsx_mrx_control_reg, reset, ==, 0, 10000)) {
162 cvmx_dprintf("SGMII%d: Timeout waiting for port %d "
163 "to finish reset\n",
164 interface, index);
165 return -1;
166 }
167 }
168
169 /*
170 * Write PCS*_MR*_CONTROL_REG[RST_AN]=1 to ensure a fresh
171 * sgmii negotiation starts.
172 */
173 control_reg.s.rst_an = 1;
174 control_reg.s.an_en = 1;
175 control_reg.s.pwr_dn = 0;
176 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
177 control_reg.u64);
178
179 /*
180 * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating
181 * that sgmii autonegotiation is complete. In MAC mode this
182 * isn't an ethernet link, but a link between Octeon and the
183 * PHY.
184 */
185 if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
186 CVMX_WAIT_FOR_FIELD64(CVMX_PCSX_MRX_STATUS_REG(index, interface),
187 union cvmx_pcsx_mrx_status_reg, an_cpt, ==, 1,
188 10000)) {
189 /* cvmx_dprintf("SGMII%d: Port %d link timeout\n", interface, index); */
190 return -1;
191 }
192 return 0;
193}
194
195/**
196 * Configure an SGMII link to the specified speed after the SERTES
197 * link is up.
198 *
199 * @interface: Interface to init
200 * @index: Index of prot on the interface
201 * @link_info: Link state to configure
202 *
203 * Returns Zero on success, negative on failure
204 */
205static int __cvmx_helper_sgmii_hardware_init_link_speed(int interface,
206 int index,
207 cvmx_helper_link_info_t
208 link_info)
209{
210 int is_enabled;
211 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
212 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
213
214 /* Disable GMX before we make any changes. Remember the enable state */
215 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
216 is_enabled = gmxx_prtx_cfg.s.en;
217 gmxx_prtx_cfg.s.en = 0;
218 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
219
220 /* Wait for GMX to be idle */
221 if (CVMX_WAIT_FOR_FIELD64
222 (CVMX_GMXX_PRTX_CFG(index, interface), union cvmx_gmxx_prtx_cfg,
223 rx_idle, ==, 1, 10000)
224 || CVMX_WAIT_FOR_FIELD64(CVMX_GMXX_PRTX_CFG(index, interface),
225 union cvmx_gmxx_prtx_cfg, tx_idle, ==, 1,
226 10000)) {
227 cvmx_dprintf
228 ("SGMII%d: Timeout waiting for port %d to be idle\n",
229 interface, index);
230 return -1;
231 }
232
233 /* Read GMX CFG again to make sure the disable completed */
234 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
235
236 /*
237 * Get the misc control for PCS. We will need to set the
238 * duplication amount.
239 */
240 pcsx_miscx_ctl_reg.u64 =
241 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
242
243 /*
244 * Use GMXENO to force the link down if the status we get says
245 * it should be down.
246 */
247 pcsx_miscx_ctl_reg.s.gmxeno = !link_info.s.link_up;
248
249 /* Only change the duplex setting if the link is up */
250 if (link_info.s.link_up)
251 gmxx_prtx_cfg.s.duplex = link_info.s.full_duplex;
252
253 /* Do speed based setting for GMX */
254 switch (link_info.s.speed) {
255 case 10:
256 gmxx_prtx_cfg.s.speed = 0;
257 gmxx_prtx_cfg.s.speed_msb = 1;
258 gmxx_prtx_cfg.s.slottime = 0;
259 /* Setting from GMX-603 */
260 pcsx_miscx_ctl_reg.s.samp_pt = 25;
261 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
262 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
263 break;
264 case 100:
265 gmxx_prtx_cfg.s.speed = 0;
266 gmxx_prtx_cfg.s.speed_msb = 0;
267 gmxx_prtx_cfg.s.slottime = 0;
268 pcsx_miscx_ctl_reg.s.samp_pt = 0x5;
269 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 64);
270 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 0);
271 break;
272 case 1000:
273 gmxx_prtx_cfg.s.speed = 1;
274 gmxx_prtx_cfg.s.speed_msb = 0;
275 gmxx_prtx_cfg.s.slottime = 1;
276 pcsx_miscx_ctl_reg.s.samp_pt = 1;
277 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(index, interface), 512);
278 cvmx_write_csr(CVMX_GMXX_TXX_BURST(index, interface), 8192);
279 break;
280 default:
281 break;
282 }
283
284 /* Write the new misc control for PCS */
285 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
286 pcsx_miscx_ctl_reg.u64);
287
288 /* Write the new GMX settings with the port still disabled */
289 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
290
291 /* Read GMX CFG again to make sure the config completed */
292 gmxx_prtx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
293
294 /* Restore the enabled / disabled state */
295 gmxx_prtx_cfg.s.en = is_enabled;
296 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface), gmxx_prtx_cfg.u64);
297
298 return 0;
299}
300
301/**
302 * Bring up the SGMII interface to be ready for packet I/O but
303 * leave I/O disabled using the GMX override. This function
304 * follows the bringup documented in 10.6.3 of the manual.
305 *
306 * @interface: Interface to bringup
307 * @num_ports: Number of ports on the interface
308 *
309 * Returns Zero on success, negative on failure
310 */
311static int __cvmx_helper_sgmii_hardware_init(int interface, int num_ports)
312{
313 int index;
314
315 __cvmx_helper_setup_gmx(interface, num_ports);
316
317 for (index = 0; index < num_ports; index++) {
318 int ipd_port = cvmx_helper_get_ipd_port(interface, index);
319 __cvmx_helper_sgmii_hardware_init_one_time(interface, index);
320 __cvmx_helper_sgmii_link_set(ipd_port,
321 __cvmx_helper_sgmii_link_get
322 (ipd_port));
323
324 }
325
326 return 0;
327}
328
329/**
330 * Probe a SGMII interface and determine the number of ports
331 * connected to it. The SGMII interface should still be down after
332 * this call.
333 *
334 * @interface: Interface to probe
335 *
336 * Returns Number of ports on the interface. Zero to disable.
337 */
338int __cvmx_helper_sgmii_probe(int interface)
339{
340 union cvmx_gmxx_inf_mode mode;
341
342 /*
343 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
344 * interface needs to be enabled before IPD otherwise per port
345 * backpressure may not work properly
346 */
347 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
348 mode.s.en = 1;
349 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
350 return 4;
351}
352
353/**
354 * Bringup and enable a SGMII interface. After this call packet
355 * I/O should be fully functional. This is called with IPD
356 * enabled but PKO disabled.
357 *
358 * @interface: Interface to bring up
359 *
360 * Returns Zero on success, negative on failure
361 */
362int __cvmx_helper_sgmii_enable(int interface)
363{
364 int num_ports = cvmx_helper_ports_on_interface(interface);
365 int index;
366
367 __cvmx_helper_sgmii_hardware_init(interface, num_ports);
368
369 for (index = 0; index < num_ports; index++) {
370 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
371 gmxx_prtx_cfg.u64 =
372 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
373 gmxx_prtx_cfg.s.en = 1;
374 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
375 gmxx_prtx_cfg.u64);
376 __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
377 }
378 __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
379 __cvmx_interrupt_gmxx_enable(interface);
380 return 0;
381}
382
383/**
384 * Return the link state of an IPD/PKO port as returned by
385 * auto negotiation. The result of this function may not match
386 * Octeon's link config if auto negotiation has changed since
387 * the last call to cvmx_helper_link_set().
388 *
389 * @ipd_port: IPD/PKO port to query
390 *
391 * Returns Link state
392 */
393cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
394{
395 cvmx_helper_link_info_t result;
396 union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
397 int interface = cvmx_helper_get_interface_num(ipd_port);
398 int index = cvmx_helper_get_interface_index_num(ipd_port);
399 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
400
401 result.u64 = 0;
402
403 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
404 /* The simulator gives you a simulated 1Gbps full duplex link */
405 result.s.link_up = 1;
406 result.s.full_duplex = 1;
407 result.s.speed = 1000;
408 return result;
409 }
410
411 pcsx_mrx_control_reg.u64 =
412 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
413 if (pcsx_mrx_control_reg.s.loopbck1) {
414 /* Force 1Gbps full duplex link for internal loopback */
415 result.s.link_up = 1;
416 result.s.full_duplex = 1;
417 result.s.speed = 1000;
418 return result;
419 }
420
421 pcs_misc_ctl_reg.u64 =
422 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
423 if (pcs_misc_ctl_reg.s.mode) {
424 /* 1000BASE-X */
425 /* FIXME */
426 } else {
427 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
428 pcsx_miscx_ctl_reg.u64 =
429 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
430 if (pcsx_miscx_ctl_reg.s.mac_phy) {
431 /* PHY Mode */
432 union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
433 union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
434
435 /*
436 * Don't bother continuing if the SERTES low
437 * level link is down
438 */
439 pcsx_mrx_status_reg.u64 =
440 cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
441 (index, interface));
442 if (pcsx_mrx_status_reg.s.lnk_st == 0) {
443 if (__cvmx_helper_sgmii_hardware_init_link
444 (interface, index) != 0)
445 return result;
446 }
447
448 /* Read the autoneg results */
449 pcsx_anx_results_reg.u64 =
450 cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
451 (index, interface));
452 if (pcsx_anx_results_reg.s.an_cpt) {
453 /*
454 * Auto negotiation is complete. Set
455 * status accordingly.
456 */
457 result.s.full_duplex =
458 pcsx_anx_results_reg.s.dup;
459 result.s.link_up =
460 pcsx_anx_results_reg.s.link_ok;
461 switch (pcsx_anx_results_reg.s.spd) {
462 case 0:
463 result.s.speed = 10;
464 break;
465 case 1:
466 result.s.speed = 100;
467 break;
468 case 2:
469 result.s.speed = 1000;
470 break;
471 default:
472 result.s.speed = 0;
473 result.s.link_up = 0;
474 break;
475 }
476 } else {
477 /*
478 * Auto negotiation isn't
479 * complete. Return link down.
480 */
481 result.s.speed = 0;
482 result.s.link_up = 0;
483 }
484 } else { /* MAC Mode */
485
486 result = __cvmx_helper_board_link_get(ipd_port);
487 }
488 }
489 return result;
490}
491
492/**
493 * Configure an IPD/PKO port for the specified link state. This
494 * function does not influence auto negotiation at the PHY level.
495 * The passed link state must always match the link state returned
496 * by cvmx_helper_link_get(). It is normally best to use
497 * cvmx_helper_link_autoconf() instead.
498 *
499 * @ipd_port: IPD/PKO port to configure
500 * @link_info: The new link state
501 *
502 * Returns Zero on success, negative on failure
503 */
504int __cvmx_helper_sgmii_link_set(int ipd_port,
505 cvmx_helper_link_info_t link_info)
506{
507 int interface = cvmx_helper_get_interface_num(ipd_port);
508 int index = cvmx_helper_get_interface_index_num(ipd_port);
509 __cvmx_helper_sgmii_hardware_init_link(interface, index);
510 return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
511 link_info);
512}
513
514/**
515 * Configure a port for internal and/or external loopback. Internal
516 * loopback causes packets sent by the port to be received by
517 * Octeon. External loopback causes packets received from the wire to
518 * sent out again.
519 *
520 * @ipd_port: IPD/PKO port to loopback.
521 * @enable_internal:
522 * Non zero if you want internal loopback
523 * @enable_external:
524 * Non zero if you want external loopback
525 *
526 * Returns Zero on success, negative on failure.
527 */
528int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal,
529 int enable_external)
530{
531 int interface = cvmx_helper_get_interface_num(ipd_port);
532 int index = cvmx_helper_get_interface_index_num(ipd_port);
533 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
534 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
535
536 pcsx_mrx_control_reg.u64 =
537 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
538 pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
539 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
540 pcsx_mrx_control_reg.u64);
541
542 pcsx_miscx_ctl_reg.u64 =
543 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
544 pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
545 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
546 pcsx_miscx_ctl_reg.u64);
547
548 __cvmx_helper_sgmii_hardware_init_link(interface, index);
549 return 0;
550}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c b/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c
new file mode 100644
index 000000000000..02a444230ef7
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c
@@ -0,0 +1,195 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28void __cvmx_interrupt_gmxx_enable(int interface);
29void __cvmx_interrupt_spxx_int_msk_enable(int index);
30void __cvmx_interrupt_stxx_int_msk_enable(int index);
31
32/*
33 * Functions for SPI initialization, configuration,
34 * and monitoring.
35 */
36#include <asm/octeon/octeon.h>
37
38#include <asm/octeon/cvmx-config.h>
39#include <asm/octeon/cvmx-spi.h>
40#include <asm/octeon/cvmx-helper.h>
41
42#include <asm/octeon/cvmx-pip-defs.h>
43#include <asm/octeon/cvmx-pko-defs.h>
44
45/*
46 * CVMX_HELPER_SPI_TIMEOUT is used to determine how long the SPI
47 * initialization routines wait for SPI training. You can override the
48 * value using executive-config.h if necessary.
49 */
50#ifndef CVMX_HELPER_SPI_TIMEOUT
51#define CVMX_HELPER_SPI_TIMEOUT 10
52#endif
53
54/**
55 * Probe a SPI interface and determine the number of ports
56 * connected to it. The SPI interface should still be down after
57 * this call.
58 *
59 * @interface: Interface to probe
60 *
61 * Returns Number of ports on the interface. Zero to disable.
62 */
63int __cvmx_helper_spi_probe(int interface)
64{
65 int num_ports = 0;
66
67 if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
68 cvmx_spi4000_is_present(interface)) {
69 num_ports = 10;
70 } else {
71 union cvmx_pko_reg_crc_enable enable;
72 num_ports = 16;
73 /*
74 * Unlike the SPI4000, most SPI devices don't
75 * automatically put on the L2 CRC. For everything
76 * except for the SPI4000 have PKO append the L2 CRC
77 * to the packet.
78 */
79 enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE);
80 enable.s.enable |= 0xffff << (interface * 16);
81 cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64);
82 }
83 __cvmx_helper_setup_gmx(interface, num_ports);
84 return num_ports;
85}
86
87/**
88 * Bringup and enable a SPI interface. After this call packet I/O
89 * should be fully functional. This is called with IPD enabled but
90 * PKO disabled.
91 *
92 * @interface: Interface to bring up
93 *
94 * Returns Zero on success, negative on failure
95 */
96int __cvmx_helper_spi_enable(int interface)
97{
98 /*
99 * Normally the ethernet L2 CRC is checked and stripped in the
100 * GMX block. When you are using SPI, this isn' the case and
101 * IPD needs to check the L2 CRC.
102 */
103 int num_ports = cvmx_helper_ports_on_interface(interface);
104 int ipd_port;
105 for (ipd_port = interface * 16; ipd_port < interface * 16 + num_ports;
106 ipd_port++) {
107 union cvmx_pip_prt_cfgx port_config;
108 port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
109 port_config.s.crc_en = 1;
110 cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_config.u64);
111 }
112
113 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
114 cvmx_spi_start_interface(interface, CVMX_SPI_MODE_DUPLEX,
115 CVMX_HELPER_SPI_TIMEOUT, num_ports);
116 if (cvmx_spi4000_is_present(interface))
117 cvmx_spi4000_initialize(interface);
118 }
119 __cvmx_interrupt_spxx_int_msk_enable(interface);
120 __cvmx_interrupt_stxx_int_msk_enable(interface);
121 __cvmx_interrupt_gmxx_enable(interface);
122 return 0;
123}
124
125/**
126 * Return the link state of an IPD/PKO port as returned by
127 * auto negotiation. The result of this function may not match
128 * Octeon's link config if auto negotiation has changed since
129 * the last call to cvmx_helper_link_set().
130 *
131 * @ipd_port: IPD/PKO port to query
132 *
133 * Returns Link state
134 */
135cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port)
136{
137 cvmx_helper_link_info_t result;
138 int interface = cvmx_helper_get_interface_num(ipd_port);
139 int index = cvmx_helper_get_interface_index_num(ipd_port);
140 result.u64 = 0;
141
142 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
143 /* The simulator gives you a simulated full duplex link */
144 result.s.link_up = 1;
145 result.s.full_duplex = 1;
146 result.s.speed = 10000;
147 } else if (cvmx_spi4000_is_present(interface)) {
148 union cvmx_gmxx_rxx_rx_inbnd inband =
149 cvmx_spi4000_check_speed(interface, index);
150 result.s.link_up = inband.s.status;
151 result.s.full_duplex = inband.s.duplex;
152 switch (inband.s.speed) {
153 case 0: /* 10 Mbps */
154 result.s.speed = 10;
155 break;
156 case 1: /* 100 Mbps */
157 result.s.speed = 100;
158 break;
159 case 2: /* 1 Gbps */
160 result.s.speed = 1000;
161 break;
162 case 3: /* Illegal */
163 result.s.speed = 0;
164 result.s.link_up = 0;
165 break;
166 }
167 } else {
168 /* For generic SPI we can't determine the link, just return some
169 sane results */
170 result.s.link_up = 1;
171 result.s.full_duplex = 1;
172 result.s.speed = 10000;
173 }
174 return result;
175}
176
177/**
178 * Configure an IPD/PKO port for the specified link state. This
179 * function does not influence auto negotiation at the PHY level.
180 * The passed link state must always match the link state returned
181 * by cvmx_helper_link_get(). It is normally best to use
182 * cvmx_helper_link_autoconf() instead.
183 *
184 * @ipd_port: IPD/PKO port to configure
185 * @link_info: The new link state
186 *
187 * Returns Zero on success, negative on failure
188 */
189int __cvmx_helper_spi_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
190{
191 /* Nothing to do. If we have a SPI4000 then the setup was already performed
192 by cvmx_spi4000_check_speed(). If not then there isn't any link
193 info */
194 return 0;
195}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c
new file mode 100644
index 000000000000..116dea17acf5
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c
@@ -0,0 +1,433 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Small helper utilities.
30 */
31#include <linux/kernel.h>
32
33#include <asm/octeon/octeon.h>
34
35#include <asm/octeon/cvmx-config.h>
36
37#include <asm/octeon/cvmx-fpa.h>
38#include <asm/octeon/cvmx-pip.h>
39#include <asm/octeon/cvmx-pko.h>
40#include <asm/octeon/cvmx-ipd.h>
41#include <asm/octeon/cvmx-spi.h>
42
43#include <asm/octeon/cvmx-helper.h>
44#include <asm/octeon/cvmx-helper-util.h>
45
46#include <asm/octeon/cvmx-ipd-defs.h>
47
48/**
49 * Convert a interface mode into a human readable string
50 *
51 * @mode: Mode to convert
52 *
53 * Returns String
54 */
55const char *cvmx_helper_interface_mode_to_string(cvmx_helper_interface_mode_t
56 mode)
57{
58 switch (mode) {
59 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
60 return "DISABLED";
61 case CVMX_HELPER_INTERFACE_MODE_RGMII:
62 return "RGMII";
63 case CVMX_HELPER_INTERFACE_MODE_GMII:
64 return "GMII";
65 case CVMX_HELPER_INTERFACE_MODE_SPI:
66 return "SPI";
67 case CVMX_HELPER_INTERFACE_MODE_PCIE:
68 return "PCIE";
69 case CVMX_HELPER_INTERFACE_MODE_XAUI:
70 return "XAUI";
71 case CVMX_HELPER_INTERFACE_MODE_SGMII:
72 return "SGMII";
73 case CVMX_HELPER_INTERFACE_MODE_PICMG:
74 return "PICMG";
75 case CVMX_HELPER_INTERFACE_MODE_NPI:
76 return "NPI";
77 case CVMX_HELPER_INTERFACE_MODE_LOOP:
78 return "LOOP";
79 }
80 return "UNKNOWN";
81}
82
83/**
84 * Debug routine to dump the packet structure to the console
85 *
86 * @work: Work queue entry containing the packet to dump
87 * Returns
88 */
89int cvmx_helper_dump_packet(cvmx_wqe_t *work)
90{
91 uint64_t count;
92 uint64_t remaining_bytes;
93 union cvmx_buf_ptr buffer_ptr;
94 uint64_t start_of_buffer;
95 uint8_t *data_address;
96 uint8_t *end_of_data;
97
98 cvmx_dprintf("Packet Length: %u\n", work->len);
99 cvmx_dprintf(" Input Port: %u\n", work->ipprt);
100 cvmx_dprintf(" QoS: %u\n", work->qos);
101 cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs);
102
103 if (work->word2.s.bufs == 0) {
104 union cvmx_ipd_wqe_fpa_queue wqe_pool;
105 wqe_pool.u64 = cvmx_read_csr(CVMX_IPD_WQE_FPA_QUEUE);
106 buffer_ptr.u64 = 0;
107 buffer_ptr.s.pool = wqe_pool.s.wqe_pool;
108 buffer_ptr.s.size = 128;
109 buffer_ptr.s.addr = cvmx_ptr_to_phys(work->packet_data);
110 if (likely(!work->word2.s.not_IP)) {
111 union cvmx_pip_ip_offset pip_ip_offset;
112 pip_ip_offset.u64 = cvmx_read_csr(CVMX_PIP_IP_OFFSET);
113 buffer_ptr.s.addr +=
114 (pip_ip_offset.s.offset << 3) -
115 work->word2.s.ip_offset;
116 buffer_ptr.s.addr += (work->word2.s.is_v6 ^ 1) << 2;
117 } else {
118 /*
119 * WARNING: This code assumes that the packet
120 * is not RAW. If it was, we would use
121 * PIP_GBL_CFG[RAW_SHF] instead of
122 * PIP_GBL_CFG[NIP_SHF].
123 */
124 union cvmx_pip_gbl_cfg pip_gbl_cfg;
125 pip_gbl_cfg.u64 = cvmx_read_csr(CVMX_PIP_GBL_CFG);
126 buffer_ptr.s.addr += pip_gbl_cfg.s.nip_shf;
127 }
128 } else
129 buffer_ptr = work->packet_ptr;
130 remaining_bytes = work->len;
131
132 while (remaining_bytes) {
133 start_of_buffer =
134 ((buffer_ptr.s.addr >> 7) - buffer_ptr.s.back) << 7;
135 cvmx_dprintf(" Buffer Start:%llx\n",
136 (unsigned long long)start_of_buffer);
137 cvmx_dprintf(" Buffer I : %u\n", buffer_ptr.s.i);
138 cvmx_dprintf(" Buffer Back: %u\n", buffer_ptr.s.back);
139 cvmx_dprintf(" Buffer Pool: %u\n", buffer_ptr.s.pool);
140 cvmx_dprintf(" Buffer Data: %llx\n",
141 (unsigned long long)buffer_ptr.s.addr);
142 cvmx_dprintf(" Buffer Size: %u\n", buffer_ptr.s.size);
143
144 cvmx_dprintf("\t\t");
145 data_address = (uint8_t *) cvmx_phys_to_ptr(buffer_ptr.s.addr);
146 end_of_data = data_address + buffer_ptr.s.size;
147 count = 0;
148 while (data_address < end_of_data) {
149 if (remaining_bytes == 0)
150 break;
151 else
152 remaining_bytes--;
153 cvmx_dprintf("%02x", (unsigned int)*data_address);
154 data_address++;
155 if (remaining_bytes && (count == 7)) {
156 cvmx_dprintf("\n\t\t");
157 count = 0;
158 } else
159 count++;
160 }
161 cvmx_dprintf("\n");
162
163 if (remaining_bytes)
164 buffer_ptr = *(union cvmx_buf_ptr *)
165 cvmx_phys_to_ptr(buffer_ptr.s.addr - 8);
166 }
167 return 0;
168}
169
170/**
171 * Setup Random Early Drop on a specific input queue
172 *
173 * @queue: Input queue to setup RED on (0-7)
174 * @pass_thresh:
175 * Packets will begin slowly dropping when there are less than
176 * this many packet buffers free in FPA 0.
177 * @drop_thresh:
178 * All incomming packets will be dropped when there are less
179 * than this many free packet buffers in FPA 0.
180 * Returns Zero on success. Negative on failure
181 */
182int cvmx_helper_setup_red_queue(int queue, int pass_thresh, int drop_thresh)
183{
184 union cvmx_ipd_qosx_red_marks red_marks;
185 union cvmx_ipd_red_quex_param red_param;
186
187 /* Set RED to begin dropping packets when there are pass_thresh buffers
188 left. It will linearly drop more packets until reaching drop_thresh
189 buffers */
190 red_marks.u64 = 0;
191 red_marks.s.drop = drop_thresh;
192 red_marks.s.pass = pass_thresh;
193 cvmx_write_csr(CVMX_IPD_QOSX_RED_MARKS(queue), red_marks.u64);
194
195 /* Use the actual queue 0 counter, not the average */
196 red_param.u64 = 0;
197 red_param.s.prb_con =
198 (255ul << 24) / (red_marks.s.pass - red_marks.s.drop);
199 red_param.s.avg_con = 1;
200 red_param.s.new_con = 255;
201 red_param.s.use_pcnt = 1;
202 cvmx_write_csr(CVMX_IPD_RED_QUEX_PARAM(queue), red_param.u64);
203 return 0;
204}
205
206/**
207 * Setup Random Early Drop to automatically begin dropping packets.
208 *
209 * @pass_thresh:
210 * Packets will begin slowly dropping when there are less than
211 * this many packet buffers free in FPA 0.
212 * @drop_thresh:
213 * All incomming packets will be dropped when there are less
214 * than this many free packet buffers in FPA 0.
215 * Returns Zero on success. Negative on failure
216 */
217int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)
218{
219 union cvmx_ipd_portx_bp_page_cnt page_cnt;
220 union cvmx_ipd_bp_prt_red_end ipd_bp_prt_red_end;
221 union cvmx_ipd_red_port_enable red_port_enable;
222 int queue;
223 int interface;
224 int port;
225
226 /* Disable backpressure based on queued buffers. It needs SW support */
227 page_cnt.u64 = 0;
228 page_cnt.s.bp_enb = 0;
229 page_cnt.s.page_cnt = 100;
230 for (interface = 0; interface < 2; interface++) {
231 for (port = cvmx_helper_get_first_ipd_port(interface);
232 port < cvmx_helper_get_last_ipd_port(interface); port++)
233 cvmx_write_csr(CVMX_IPD_PORTX_BP_PAGE_CNT(port),
234 page_cnt.u64);
235 }
236
237 for (queue = 0; queue < 8; queue++)
238 cvmx_helper_setup_red_queue(queue, pass_thresh, drop_thresh);
239
240 /* Shutoff the dropping based on the per port page count. SW isn't
241 decrementing it right now */
242 ipd_bp_prt_red_end.u64 = 0;
243 ipd_bp_prt_red_end.s.prt_enb = 0;
244 cvmx_write_csr(CVMX_IPD_BP_PRT_RED_END, ipd_bp_prt_red_end.u64);
245
246 red_port_enable.u64 = 0;
247 red_port_enable.s.prt_enb = 0xfffffffffull;
248 red_port_enable.s.avg_dly = 10000;
249 red_port_enable.s.prb_dly = 10000;
250 cvmx_write_csr(CVMX_IPD_RED_PORT_ENABLE, red_port_enable.u64);
251
252 return 0;
253}
254
255/**
256 * Setup the common GMX settings that determine the number of
257 * ports. These setting apply to almost all configurations of all
258 * chips.
259 *
260 * @interface: Interface to configure
261 * @num_ports: Number of ports on the interface
262 *
263 * Returns Zero on success, negative on failure
264 */
265int __cvmx_helper_setup_gmx(int interface, int num_ports)
266{
267 union cvmx_gmxx_tx_prts gmx_tx_prts;
268 union cvmx_gmxx_rx_prts gmx_rx_prts;
269 union cvmx_pko_reg_gmx_port_mode pko_mode;
270 union cvmx_gmxx_txx_thresh gmx_tx_thresh;
271 int index;
272
273 /* Tell GMX the number of TX ports on this interface */
274 gmx_tx_prts.u64 = cvmx_read_csr(CVMX_GMXX_TX_PRTS(interface));
275 gmx_tx_prts.s.prts = num_ports;
276 cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), gmx_tx_prts.u64);
277
278 /* Tell GMX the number of RX ports on this interface. This only
279 ** applies to *GMII and XAUI ports */
280 if (cvmx_helper_interface_get_mode(interface) ==
281 CVMX_HELPER_INTERFACE_MODE_RGMII
282 || cvmx_helper_interface_get_mode(interface) ==
283 CVMX_HELPER_INTERFACE_MODE_SGMII
284 || cvmx_helper_interface_get_mode(interface) ==
285 CVMX_HELPER_INTERFACE_MODE_GMII
286 || cvmx_helper_interface_get_mode(interface) ==
287 CVMX_HELPER_INTERFACE_MODE_XAUI) {
288 if (num_ports > 4) {
289 cvmx_dprintf("__cvmx_helper_setup_gmx: Illegal "
290 "num_ports\n");
291 return -1;
292 }
293
294 gmx_rx_prts.u64 = cvmx_read_csr(CVMX_GMXX_RX_PRTS(interface));
295 gmx_rx_prts.s.prts = num_ports;
296 cvmx_write_csr(CVMX_GMXX_RX_PRTS(interface), gmx_rx_prts.u64);
297 }
298
299 /* Skip setting CVMX_PKO_REG_GMX_PORT_MODE on 30XX, 31XX, and 50XX */
300 if (!OCTEON_IS_MODEL(OCTEON_CN30XX) && !OCTEON_IS_MODEL(OCTEON_CN31XX)
301 && !OCTEON_IS_MODEL(OCTEON_CN50XX)) {
302 /* Tell PKO the number of ports on this interface */
303 pko_mode.u64 = cvmx_read_csr(CVMX_PKO_REG_GMX_PORT_MODE);
304 if (interface == 0) {
305 if (num_ports == 1)
306 pko_mode.s.mode0 = 4;
307 else if (num_ports == 2)
308 pko_mode.s.mode0 = 3;
309 else if (num_ports <= 4)
310 pko_mode.s.mode0 = 2;
311 else if (num_ports <= 8)
312 pko_mode.s.mode0 = 1;
313 else
314 pko_mode.s.mode0 = 0;
315 } else {
316 if (num_ports == 1)
317 pko_mode.s.mode1 = 4;
318 else if (num_ports == 2)
319 pko_mode.s.mode1 = 3;
320 else if (num_ports <= 4)
321 pko_mode.s.mode1 = 2;
322 else if (num_ports <= 8)
323 pko_mode.s.mode1 = 1;
324 else
325 pko_mode.s.mode1 = 0;
326 }
327 cvmx_write_csr(CVMX_PKO_REG_GMX_PORT_MODE, pko_mode.u64);
328 }
329
330 /*
331 * Set GMX to buffer as much data as possible before starting
332 * transmit. This reduces the chances that we have a TX under
333 * run due to memory contention. Any packet that fits entirely
334 * in the GMX FIFO can never have an under run regardless of
335 * memory load.
336 */
337 gmx_tx_thresh.u64 = cvmx_read_csr(CVMX_GMXX_TXX_THRESH(0, interface));
338 if (OCTEON_IS_MODEL(OCTEON_CN30XX) || OCTEON_IS_MODEL(OCTEON_CN31XX)
339 || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
340 /* These chips have a fixed max threshold of 0x40 */
341 gmx_tx_thresh.s.cnt = 0x40;
342 } else {
343 /* Choose the max value for the number of ports */
344 if (num_ports <= 1)
345 gmx_tx_thresh.s.cnt = 0x100 / 1;
346 else if (num_ports == 2)
347 gmx_tx_thresh.s.cnt = 0x100 / 2;
348 else
349 gmx_tx_thresh.s.cnt = 0x100 / 4;
350 }
351 /*
352 * SPI and XAUI can have lots of ports but the GMX hardware
353 * only ever has a max of 4.
354 */
355 if (num_ports > 4)
356 num_ports = 4;
357 for (index = 0; index < num_ports; index++)
358 cvmx_write_csr(CVMX_GMXX_TXX_THRESH(index, interface),
359 gmx_tx_thresh.u64);
360
361 return 0;
362}
363
364/**
365 * Returns the IPD/PKO port number for a port on the given
366 * interface.
367 *
368 * @interface: Interface to use
369 * @port: Port on the interface
370 *
371 * Returns IPD/PKO port number
372 */
373int cvmx_helper_get_ipd_port(int interface, int port)
374{
375 switch (interface) {
376 case 0:
377 return port;
378 case 1:
379 return port + 16;
380 case 2:
381 return port + 32;
382 case 3:
383 return port + 36;
384 }
385 return -1;
386}
387
388/**
389 * Returns the interface number for an IPD/PKO port number.
390 *
391 * @ipd_port: IPD/PKO port number
392 *
393 * Returns Interface number
394 */
395int cvmx_helper_get_interface_num(int ipd_port)
396{
397 if (ipd_port < 16)
398 return 0;
399 else if (ipd_port < 32)
400 return 1;
401 else if (ipd_port < 36)
402 return 2;
403 else if (ipd_port < 40)
404 return 3;
405 else
406 cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD "
407 "port number\n");
408
409 return -1;
410}
411
412/**
413 * Returns the interface index number for an IPD/PKO port
414 * number.
415 *
416 * @ipd_port: IPD/PKO port number
417 *
418 * Returns Interface index number
419 */
420int cvmx_helper_get_interface_index_num(int ipd_port)
421{
422 if (ipd_port < 32)
423 return ipd_port & 15;
424 else if (ipd_port < 36)
425 return ipd_port & 3;
426 else if (ipd_port < 40)
427 return ipd_port & 3;
428 else
429 cvmx_dprintf("cvmx_helper_get_interface_index_num: "
430 "Illegal IPD port number\n");
431
432 return -1;
433}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
new file mode 100644
index 000000000000..667a8e3cb142
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
@@ -0,0 +1,348 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Functions for XAUI initialization, configuration,
30 * and monitoring.
31 *
32 */
33
34#include <asm/octeon/octeon.h>
35
36#include <asm/octeon/cvmx-config.h>
37
38#include <asm/octeon/cvmx-helper.h>
39
40#include <asm/octeon/cvmx-pko-defs.h>
41#include <asm/octeon/cvmx-gmxx-defs.h>
42#include <asm/octeon/cvmx-pcsxx-defs.h>
43
44void __cvmx_interrupt_gmxx_enable(int interface);
45void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block);
46void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index);
47/**
48 * Probe a XAUI interface and determine the number of ports
49 * connected to it. The XAUI interface should still be down
50 * after this call.
51 *
52 * @interface: Interface to probe
53 *
54 * Returns Number of ports on the interface. Zero to disable.
55 */
56int __cvmx_helper_xaui_probe(int interface)
57{
58 int i;
59 union cvmx_gmxx_hg2_control gmx_hg2_control;
60 union cvmx_gmxx_inf_mode mode;
61
62 /*
63 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
64 * interface needs to be enabled before IPD otherwise per port
65 * backpressure may not work properly.
66 */
67 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
68 mode.s.en = 1;
69 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
70
71 __cvmx_helper_setup_gmx(interface, 1);
72
73 /*
74 * Setup PKO to support 16 ports for HiGig2 virtual
75 * ports. We're pointing all of the PKO packet ports for this
76 * interface to the XAUI. This allows us to use HiGig2
77 * backpressure per port.
78 */
79 for (i = 0; i < 16; i++) {
80 union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs;
81 pko_mem_port_ptrs.u64 = 0;
82 /*
83 * We set each PKO port to have equal priority in a
84 * round robin fashion.
85 */
86 pko_mem_port_ptrs.s.static_p = 0;
87 pko_mem_port_ptrs.s.qos_mask = 0xff;
88 /* All PKO ports map to the same XAUI hardware port */
89 pko_mem_port_ptrs.s.eid = interface * 4;
90 pko_mem_port_ptrs.s.pid = interface * 16 + i;
91 cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
92 }
93
94 /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
95 gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
96 if (gmx_hg2_control.s.hg2tx_en)
97 return 16;
98 else
99 return 1;
100}
101
102/**
103 * Bringup and enable a XAUI interface. After this call packet
104 * I/O should be fully functional. This is called with IPD
105 * enabled but PKO disabled.
106 *
107 * @interface: Interface to bring up
108 *
109 * Returns Zero on success, negative on failure
110 */
111int __cvmx_helper_xaui_enable(int interface)
112{
113 union cvmx_gmxx_prtx_cfg gmx_cfg;
114 union cvmx_pcsxx_control1_reg xauiCtl;
115 union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl;
116 union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl;
117 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
118 union cvmx_gmxx_tx_int_en gmx_tx_int_en;
119 union cvmx_pcsxx_int_en_reg pcsx_int_en_reg;
120
121 /* (1) Interface has already been enabled. */
122
123 /* (2) Disable GMX. */
124 xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
125 xauiMiscCtl.s.gmxeno = 1;
126 cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
127
128 /* (3) Disable GMX and PCSX interrupts. */
129 gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface));
130 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
131 gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface));
132 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
133 pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface));
134 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
135
136 /* (4) Bring up the PCSX and GMX reconciliation layer. */
137 /* (4)a Set polarity and lane swapping. */
138 /* (4)b */
139 gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
140 /* Enable better IFG packing and improves performance */
141 gmxXauiTxCtl.s.dic_en = 1;
142 gmxXauiTxCtl.s.uni_en = 0;
143 cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
144
145 /* (4)c Aply reset sequence */
146 xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
147 xauiCtl.s.lo_pwr = 0;
148 xauiCtl.s.reset = 1;
149 cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
150
151 /* Wait for PCS to come out of reset */
152 if (CVMX_WAIT_FOR_FIELD64
153 (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg,
154 reset, ==, 0, 10000))
155 return -1;
156 /* Wait for PCS to be aligned */
157 if (CVMX_WAIT_FOR_FIELD64
158 (CVMX_PCSXX_10GBX_STATUS_REG(interface),
159 union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000))
160 return -1;
161 /* Wait for RX to be ready */
162 if (CVMX_WAIT_FOR_FIELD64
163 (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl,
164 status, ==, 0, 10000))
165 return -1;
166
167 /* (6) Configure GMX */
168 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
169 gmx_cfg.s.en = 0;
170 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
171
172 /* Wait for GMX RX to be idle */
173 if (CVMX_WAIT_FOR_FIELD64
174 (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
175 rx_idle, ==, 1, 10000))
176 return -1;
177 /* Wait for GMX TX to be idle */
178 if (CVMX_WAIT_FOR_FIELD64
179 (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
180 tx_idle, ==, 1, 10000))
181 return -1;
182
183 /* GMX configure */
184 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
185 gmx_cfg.s.speed = 1;
186 gmx_cfg.s.speed_msb = 0;
187 gmx_cfg.s.slottime = 1;
188 cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
189 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
190 cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
191 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
192
193 /* (7) Clear out any error state */
194 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface),
195 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface)));
196 cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface),
197 cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface)));
198 cvmx_write_csr(CVMX_PCSXX_INT_REG(interface),
199 cvmx_read_csr(CVMX_PCSXX_INT_REG(interface)));
200
201 /* Wait for receive link */
202 if (CVMX_WAIT_FOR_FIELD64
203 (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg,
204 rcv_lnk, ==, 1, 10000))
205 return -1;
206 if (CVMX_WAIT_FOR_FIELD64
207 (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
208 xmtflt, ==, 0, 10000))
209 return -1;
210 if (CVMX_WAIT_FOR_FIELD64
211 (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
212 rcvflt, ==, 0, 10000))
213 return -1;
214
215 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64);
216 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64);
217 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64);
218
219 cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0));
220
221 /* (8) Enable packet reception */
222 xauiMiscCtl.s.gmxeno = 0;
223 cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
224
225 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
226 gmx_cfg.s.en = 1;
227 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
228
229 __cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface);
230 __cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface);
231 __cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface);
232 __cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface);
233 __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
234 __cvmx_interrupt_gmxx_enable(interface);
235
236 return 0;
237}
238
239/**
240 * Return the link state of an IPD/PKO port as returned by
241 * auto negotiation. The result of this function may not match
242 * Octeon's link config if auto negotiation has changed since
243 * the last call to cvmx_helper_link_set().
244 *
245 * @ipd_port: IPD/PKO port to query
246 *
247 * Returns Link state
248 */
249cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
250{
251 int interface = cvmx_helper_get_interface_num(ipd_port);
252 union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
253 union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
254 union cvmx_pcsxx_status1_reg pcsxx_status1_reg;
255 cvmx_helper_link_info_t result;
256
257 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
258 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
259 pcsxx_status1_reg.u64 =
260 cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
261 result.u64 = 0;
262
263 /* Only return a link if both RX and TX are happy */
264 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
265 (pcsxx_status1_reg.s.rcv_lnk == 1)) {
266 result.s.link_up = 1;
267 result.s.full_duplex = 1;
268 result.s.speed = 10000;
269 } else {
270 /* Disable GMX and PCSX interrupts. */
271 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
272 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
273 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
274 }
275 return result;
276}
277
278/**
279 * Configure an IPD/PKO port for the specified link state. This
280 * function does not influence auto negotiation at the PHY level.
281 * The passed link state must always match the link state returned
282 * by cvmx_helper_link_get(). It is normally best to use
283 * cvmx_helper_link_autoconf() instead.
284 *
285 * @ipd_port: IPD/PKO port to configure
286 * @link_info: The new link state
287 *
288 * Returns Zero on success, negative on failure
289 */
290int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
291{
292 int interface = cvmx_helper_get_interface_num(ipd_port);
293 union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
294 union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
295
296 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
297 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
298
299 /* If the link shouldn't be up, then just return */
300 if (!link_info.s.link_up)
301 return 0;
302
303 /* Do nothing if both RX and TX are happy */
304 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
305 return 0;
306
307 /* Bring the link up */
308 return __cvmx_helper_xaui_enable(interface);
309}
310
311/**
312 * Configure a port for internal and/or external loopback. Internal loopback
313 * causes packets sent by the port to be received by Octeon. External loopback
314 * causes packets received from the wire to sent out again.
315 *
316 * @ipd_port: IPD/PKO port to loopback.
317 * @enable_internal:
318 * Non zero if you want internal loopback
319 * @enable_external:
320 * Non zero if you want external loopback
321 *
322 * Returns Zero on success, negative on failure.
323 */
324extern int __cvmx_helper_xaui_configure_loopback(int ipd_port,
325 int enable_internal,
326 int enable_external)
327{
328 int interface = cvmx_helper_get_interface_num(ipd_port);
329 union cvmx_pcsxx_control1_reg pcsxx_control1_reg;
330 union cvmx_gmxx_xaui_ext_loopback gmxx_xaui_ext_loopback;
331
332 /* Set the internal loop */
333 pcsxx_control1_reg.u64 =
334 cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
335 pcsxx_control1_reg.s.loopbck1 = enable_internal;
336 cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface),
337 pcsxx_control1_reg.u64);
338
339 /* Set the external loop */
340 gmxx_xaui_ext_loopback.u64 =
341 cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface));
342 gmxx_xaui_ext_loopback.s.en = enable_external;
343 cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface),
344 gmxx_xaui_ext_loopback.u64);
345
346 /* Take the link through a reset */
347 return __cvmx_helper_xaui_enable(interface);
348}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c
new file mode 100644
index 000000000000..daa8c8bbcfe4
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c
@@ -0,0 +1,1053 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 *
30 * Helper functions for common, but complicated tasks.
31 *
32 */
33#include <asm/octeon/octeon.h>
34
35#include <asm/octeon/cvmx-config.h>
36
37#include <asm/octeon/cvmx-fpa.h>
38#include <asm/octeon/cvmx-pip.h>
39#include <asm/octeon/cvmx-pko.h>
40#include <asm/octeon/cvmx-ipd.h>
41#include <asm/octeon/cvmx-spi.h>
42#include <asm/octeon/cvmx-helper.h>
43#include <asm/octeon/cvmx-helper-board.h>
44
45#include <asm/octeon/cvmx-pip-defs.h>
46#include <asm/octeon/cvmx-smix-defs.h>
47#include <asm/octeon/cvmx-asxx-defs.h>
48
49/**
50 * cvmx_override_pko_queue_priority(int ipd_port, uint64_t
51 * priorities[16]) is a function pointer. It is meant to allow
52 * customization of the PKO queue priorities based on the port
53 * number. Users should set this pointer to a function before
54 * calling any cvmx-helper operations.
55 */
56void (*cvmx_override_pko_queue_priority) (int pko_port,
57 uint64_t priorities[16]);
58
59/**
60 * cvmx_override_ipd_port_setup(int ipd_port) is a function
61 * pointer. It is meant to allow customization of the IPD port
62 * setup before packet input/output comes online. It is called
63 * after cvmx-helper does the default IPD configuration, but
64 * before IPD is enabled. Users should set this pointer to a
65 * function before calling any cvmx-helper operations.
66 */
67void (*cvmx_override_ipd_port_setup) (int ipd_port);
68
69/* Port count per interface */
70static int interface_port_count[4] = { 0, 0, 0, 0 };
71
72/* Port last configured link info index by IPD/PKO port */
73static cvmx_helper_link_info_t
74 port_link_info[CVMX_PIP_NUM_INPUT_PORTS];
75
76/**
77 * Return the number of interfaces the chip has. Each interface
78 * may have multiple ports. Most chips support two interfaces,
79 * but the CNX0XX and CNX1XX are exceptions. These only support
80 * one interface.
81 *
82 * Returns Number of interfaces on chip
83 */
84int cvmx_helper_get_number_of_interfaces(void)
85{
86 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX))
87 return 4;
88 else
89 return 3;
90}
91
92/**
93 * Return the number of ports on an interface. Depending on the
94 * chip and configuration, this can be 1-16. A value of 0
95 * specifies that the interface doesn't exist or isn't usable.
96 *
97 * @interface: Interface to get the port count for
98 *
99 * Returns Number of ports on interface. Can be Zero.
100 */
101int cvmx_helper_ports_on_interface(int interface)
102{
103 return interface_port_count[interface];
104}
105
106/**
107 * Get the operating mode of an interface. Depending on the Octeon
108 * chip and configuration, this function returns an enumeration
109 * of the type of packet I/O supported by an interface.
110 *
111 * @interface: Interface to probe
112 *
113 * Returns Mode of the interface. Unknown or unsupported interfaces return
114 * DISABLED.
115 */
116cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface)
117{
118 union cvmx_gmxx_inf_mode mode;
119 if (interface == 2)
120 return CVMX_HELPER_INTERFACE_MODE_NPI;
121
122 if (interface == 3) {
123 if (OCTEON_IS_MODEL(OCTEON_CN56XX)
124 || OCTEON_IS_MODEL(OCTEON_CN52XX))
125 return CVMX_HELPER_INTERFACE_MODE_LOOP;
126 else
127 return CVMX_HELPER_INTERFACE_MODE_DISABLED;
128 }
129
130 if (interface == 0
131 && cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5
132 && cvmx_sysinfo_get()->board_rev_major == 1) {
133 /*
134 * Lie about interface type of CN3005 board. This
135 * board has a switch on port 1 like the other
136 * evaluation boards, but it is connected over RGMII
137 * instead of GMII. Report GMII mode so that the
138 * speed is forced to 1 Gbit full duplex. Other than
139 * some initial configuration (which does not use the
140 * output of this function) there is no difference in
141 * setup between GMII and RGMII modes.
142 */
143 return CVMX_HELPER_INTERFACE_MODE_GMII;
144 }
145
146 /* Interface 1 is always disabled on CN31XX and CN30XX */
147 if ((interface == 1)
148 && (OCTEON_IS_MODEL(OCTEON_CN31XX) || OCTEON_IS_MODEL(OCTEON_CN30XX)
149 || OCTEON_IS_MODEL(OCTEON_CN50XX)
150 || OCTEON_IS_MODEL(OCTEON_CN52XX)))
151 return CVMX_HELPER_INTERFACE_MODE_DISABLED;
152
153 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
154
155 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
156 switch (mode.cn56xx.mode) {
157 case 0:
158 return CVMX_HELPER_INTERFACE_MODE_DISABLED;
159 case 1:
160 return CVMX_HELPER_INTERFACE_MODE_XAUI;
161 case 2:
162 return CVMX_HELPER_INTERFACE_MODE_SGMII;
163 case 3:
164 return CVMX_HELPER_INTERFACE_MODE_PICMG;
165 default:
166 return CVMX_HELPER_INTERFACE_MODE_DISABLED;
167 }
168 } else {
169 if (!mode.s.en)
170 return CVMX_HELPER_INTERFACE_MODE_DISABLED;
171
172 if (mode.s.type) {
173 if (OCTEON_IS_MODEL(OCTEON_CN38XX)
174 || OCTEON_IS_MODEL(OCTEON_CN58XX))
175 return CVMX_HELPER_INTERFACE_MODE_SPI;
176 else
177 return CVMX_HELPER_INTERFACE_MODE_GMII;
178 } else
179 return CVMX_HELPER_INTERFACE_MODE_RGMII;
180 }
181}
182
183/**
184 * Configure the IPD/PIP tagging and QoS options for a specific
185 * port. This function determines the POW work queue entry
186 * contents for a port. The setup performed here is controlled by
187 * the defines in executive-config.h.
188 *
189 * @ipd_port: Port to configure. This follows the IPD numbering, not the
190 * per interface numbering
191 *
192 * Returns Zero on success, negative on failure
193 */
194static int __cvmx_helper_port_setup_ipd(int ipd_port)
195{
196 union cvmx_pip_prt_cfgx port_config;
197 union cvmx_pip_prt_tagx tag_config;
198
199 port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
200 tag_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_TAGX(ipd_port));
201
202 /* Have each port go to a different POW queue */
203 port_config.s.qos = ipd_port & 0x7;
204
205 /* Process the headers and place the IP header in the work queue */
206 port_config.s.mode = CVMX_HELPER_INPUT_PORT_SKIP_MODE;
207
208 tag_config.s.ip6_src_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_IP;
209 tag_config.s.ip6_dst_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_IP;
210 tag_config.s.ip6_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_SRC_PORT;
211 tag_config.s.ip6_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV6_DST_PORT;
212 tag_config.s.ip6_nxth_flag = CVMX_HELPER_INPUT_TAG_IPV6_NEXT_HEADER;
213 tag_config.s.ip4_src_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_IP;
214 tag_config.s.ip4_dst_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_IP;
215 tag_config.s.ip4_sprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_SRC_PORT;
216 tag_config.s.ip4_dprt_flag = CVMX_HELPER_INPUT_TAG_IPV4_DST_PORT;
217 tag_config.s.ip4_pctl_flag = CVMX_HELPER_INPUT_TAG_IPV4_PROTOCOL;
218 tag_config.s.inc_prt_flag = CVMX_HELPER_INPUT_TAG_INPUT_PORT;
219 tag_config.s.tcp6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
220 tag_config.s.tcp4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
221 tag_config.s.ip6_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
222 tag_config.s.ip4_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
223 tag_config.s.non_tag_type = CVMX_HELPER_INPUT_TAG_TYPE;
224 /* Put all packets in group 0. Other groups can be used by the app */
225 tag_config.s.grp = 0;
226
227 cvmx_pip_config_port(ipd_port, port_config, tag_config);
228
229 /* Give the user a chance to override our setting for each port */
230 if (cvmx_override_ipd_port_setup)
231 cvmx_override_ipd_port_setup(ipd_port);
232
233 return 0;
234}
235
236/**
237 * This function probes an interface to determine the actual
238 * number of hardware ports connected to it. It doesn't setup the
239 * ports or enable them. The main goal here is to set the global
240 * interface_port_count[interface] correctly. Hardware setup of the
241 * ports will be performed later.
242 *
243 * @interface: Interface to probe
244 *
245 * Returns Zero on success, negative on failure
246 */
247int cvmx_helper_interface_probe(int interface)
248{
249 /* At this stage in the game we don't want packets to be moving yet.
250 The following probe calls should perform hardware setup
251 needed to determine port counts. Receive must still be disabled */
252 switch (cvmx_helper_interface_get_mode(interface)) {
253 /* These types don't support ports to IPD/PKO */
254 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
255 case CVMX_HELPER_INTERFACE_MODE_PCIE:
256 interface_port_count[interface] = 0;
257 break;
258 /* XAUI is a single high speed port */
259 case CVMX_HELPER_INTERFACE_MODE_XAUI:
260 interface_port_count[interface] =
261 __cvmx_helper_xaui_probe(interface);
262 break;
263 /*
264 * RGMII/GMII/MII are all treated about the same. Most
265 * functions refer to these ports as RGMII.
266 */
267 case CVMX_HELPER_INTERFACE_MODE_RGMII:
268 case CVMX_HELPER_INTERFACE_MODE_GMII:
269 interface_port_count[interface] =
270 __cvmx_helper_rgmii_probe(interface);
271 break;
272 /*
273 * SPI4 can have 1-16 ports depending on the device at
274 * the other end.
275 */
276 case CVMX_HELPER_INTERFACE_MODE_SPI:
277 interface_port_count[interface] =
278 __cvmx_helper_spi_probe(interface);
279 break;
280 /*
281 * SGMII can have 1-4 ports depending on how many are
282 * hooked up.
283 */
284 case CVMX_HELPER_INTERFACE_MODE_SGMII:
285 case CVMX_HELPER_INTERFACE_MODE_PICMG:
286 interface_port_count[interface] =
287 __cvmx_helper_sgmii_probe(interface);
288 break;
289 /* PCI target Network Packet Interface */
290 case CVMX_HELPER_INTERFACE_MODE_NPI:
291 interface_port_count[interface] =
292 __cvmx_helper_npi_probe(interface);
293 break;
294 /*
295 * Special loopback only ports. These are not the same
296 * as other ports in loopback mode.
297 */
298 case CVMX_HELPER_INTERFACE_MODE_LOOP:
299 interface_port_count[interface] =
300 __cvmx_helper_loop_probe(interface);
301 break;
302 }
303
304 interface_port_count[interface] =
305 __cvmx_helper_board_interface_probe(interface,
306 interface_port_count
307 [interface]);
308
309 /* Make sure all global variables propagate to other cores */
310 CVMX_SYNCWS;
311
312 return 0;
313}
314
315/**
316 * Setup the IPD/PIP for the ports on an interface. Packet
317 * classification and tagging are set for every port on the
318 * interface. The number of ports on the interface must already
319 * have been probed.
320 *
321 * @interface: Interface to setup IPD/PIP for
322 *
323 * Returns Zero on success, negative on failure
324 */
325static int __cvmx_helper_interface_setup_ipd(int interface)
326{
327 int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
328 int num_ports = interface_port_count[interface];
329
330 while (num_ports--) {
331 __cvmx_helper_port_setup_ipd(ipd_port);
332 ipd_port++;
333 }
334 return 0;
335}
336
337/**
338 * Setup global setting for IPD/PIP not related to a specific
339 * interface or port. This must be called before IPD is enabled.
340 *
341 * Returns Zero on success, negative on failure.
342 */
343static int __cvmx_helper_global_setup_ipd(void)
344{
345 /* Setup the global packet input options */
346 cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE / 8,
347 CVMX_HELPER_FIRST_MBUFF_SKIP / 8,
348 CVMX_HELPER_NOT_FIRST_MBUFF_SKIP / 8,
349 /* The +8 is to account for the next ptr */
350 (CVMX_HELPER_FIRST_MBUFF_SKIP + 8) / 128,
351 /* The +8 is to account for the next ptr */
352 (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP + 8) / 128,
353 CVMX_FPA_WQE_POOL,
354 CVMX_IPD_OPC_MODE_STT,
355 CVMX_HELPER_ENABLE_BACK_PRESSURE);
356 return 0;
357}
358
359/**
360 * Setup the PKO for the ports on an interface. The number of
361 * queues per port and the priority of each PKO output queue
362 * is set here. PKO must be disabled when this function is called.
363 *
364 * @interface: Interface to setup PKO for
365 *
366 * Returns Zero on success, negative on failure
367 */
368static int __cvmx_helper_interface_setup_pko(int interface)
369{
370 /*
371 * Each packet output queue has an associated priority. The
372 * higher the priority, the more often it can send a packet. A
373 * priority of 8 means it can send in all 8 rounds of
374 * contention. We're going to make each queue one less than
375 * the last. The vector of priorities has been extended to
376 * support CN5xxx CPUs, where up to 16 queues can be
377 * associated to a port. To keep backward compatibility we
378 * don't change the initial 8 priorities and replicate them in
379 * the second half. With per-core PKO queues (PKO lockless
380 * operation) all queues have the same priority.
381 */
382 uint64_t priorities[16] =
383 { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 };
384
385 /*
386 * Setup the IPD/PIP and PKO for the ports discovered
387 * above. Here packet classification, tagging and output
388 * priorities are set.
389 */
390 int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
391 int num_ports = interface_port_count[interface];
392 while (num_ports--) {
393 /*
394 * Give the user a chance to override the per queue
395 * priorities.
396 */
397 if (cvmx_override_pko_queue_priority)
398 cvmx_override_pko_queue_priority(ipd_port, priorities);
399
400 cvmx_pko_config_port(ipd_port,
401 cvmx_pko_get_base_queue_per_core(ipd_port,
402 0),
403 cvmx_pko_get_num_queues(ipd_port),
404 priorities);
405 ipd_port++;
406 }
407 return 0;
408}
409
410/**
411 * Setup global setting for PKO not related to a specific
412 * interface or port. This must be called before PKO is enabled.
413 *
414 * Returns Zero on success, negative on failure.
415 */
416static int __cvmx_helper_global_setup_pko(void)
417{
418 /*
419 * Disable tagwait FAU timeout. This needs to be done before
420 * anyone might start packet output using tags.
421 */
422 union cvmx_iob_fau_timeout fau_to;
423 fau_to.u64 = 0;
424 fau_to.s.tout_val = 0xfff;
425 fau_to.s.tout_enb = 0;
426 cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64);
427 return 0;
428}
429
430/**
431 * Setup global backpressure setting.
432 *
433 * Returns Zero on success, negative on failure
434 */
435static int __cvmx_helper_global_setup_backpressure(void)
436{
437#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
438 /* Disable backpressure if configured to do so */
439 /* Disable backpressure (pause frame) generation */
440 int num_interfaces = cvmx_helper_get_number_of_interfaces();
441 int interface;
442 for (interface = 0; interface < num_interfaces; interface++) {
443 switch (cvmx_helper_interface_get_mode(interface)) {
444 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
445 case CVMX_HELPER_INTERFACE_MODE_PCIE:
446 case CVMX_HELPER_INTERFACE_MODE_NPI:
447 case CVMX_HELPER_INTERFACE_MODE_LOOP:
448 case CVMX_HELPER_INTERFACE_MODE_XAUI:
449 break;
450 case CVMX_HELPER_INTERFACE_MODE_RGMII:
451 case CVMX_HELPER_INTERFACE_MODE_GMII:
452 case CVMX_HELPER_INTERFACE_MODE_SPI:
453 case CVMX_HELPER_INTERFACE_MODE_SGMII:
454 case CVMX_HELPER_INTERFACE_MODE_PICMG:
455 cvmx_gmx_set_backpressure_override(interface, 0xf);
456 break;
457 }
458 }
459#endif
460
461 return 0;
462}
463
464/**
465 * Enable packet input/output from the hardware. This function is
466 * called after all internal setup is complete and IPD is enabled.
467 * After this function completes, packets will be accepted from the
468 * hardware ports. PKO should still be disabled to make sure packets
469 * aren't sent out partially setup hardware.
470 *
471 * @interface: Interface to enable
472 *
473 * Returns Zero on success, negative on failure
474 */
475static int __cvmx_helper_packet_hardware_enable(int interface)
476{
477 int result = 0;
478 switch (cvmx_helper_interface_get_mode(interface)) {
479 /* These types don't support ports to IPD/PKO */
480 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
481 case CVMX_HELPER_INTERFACE_MODE_PCIE:
482 /* Nothing to do */
483 break;
484 /* XAUI is a single high speed port */
485 case CVMX_HELPER_INTERFACE_MODE_XAUI:
486 result = __cvmx_helper_xaui_enable(interface);
487 break;
488 /*
489 * RGMII/GMII/MII are all treated about the same. Most
490 * functions refer to these ports as RGMII
491 */
492 case CVMX_HELPER_INTERFACE_MODE_RGMII:
493 case CVMX_HELPER_INTERFACE_MODE_GMII:
494 result = __cvmx_helper_rgmii_enable(interface);
495 break;
496 /*
497 * SPI4 can have 1-16 ports depending on the device at
498 * the other end
499 */
500 case CVMX_HELPER_INTERFACE_MODE_SPI:
501 result = __cvmx_helper_spi_enable(interface);
502 break;
503 /*
504 * SGMII can have 1-4 ports depending on how many are
505 * hooked up
506 */
507 case CVMX_HELPER_INTERFACE_MODE_SGMII:
508 case CVMX_HELPER_INTERFACE_MODE_PICMG:
509 result = __cvmx_helper_sgmii_enable(interface);
510 break;
511 /* PCI target Network Packet Interface */
512 case CVMX_HELPER_INTERFACE_MODE_NPI:
513 result = __cvmx_helper_npi_enable(interface);
514 break;
515 /*
516 * Special loopback only ports. These are not the same
517 * as other ports in loopback mode
518 */
519 case CVMX_HELPER_INTERFACE_MODE_LOOP:
520 result = __cvmx_helper_loop_enable(interface);
521 break;
522 }
523 result |= __cvmx_helper_board_hardware_enable(interface);
524 return result;
525}
526
527/**
528 * Function to adjust internal IPD pointer alignments
529 *
530 * Returns 0 on success
531 * !0 on failure
532 */
533int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
534{
535#define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES \
536 (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP)
537#define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES \
538 (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP)
539#define FIX_IPD_OUTPORT 0
540 /* Ports 0-15 are interface 0, 16-31 are interface 1 */
541#define INTERFACE(port) (port >> 4)
542#define INDEX(port) (port & 0xf)
543 uint64_t *p64;
544 cvmx_pko_command_word0_t pko_command;
545 union cvmx_buf_ptr g_buffer, pkt_buffer;
546 cvmx_wqe_t *work;
547 int size, num_segs = 0, wqe_pcnt, pkt_pcnt;
548 union cvmx_gmxx_prtx_cfg gmx_cfg;
549 int retry_cnt;
550 int retry_loop_cnt;
551 int i;
552 cvmx_helper_link_info_t link_info;
553
554 /* Save values for restore at end */
555 uint64_t prtx_cfg =
556 cvmx_read_csr(CVMX_GMXX_PRTX_CFG
557 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
558 uint64_t tx_ptr_en =
559 cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
560 uint64_t rx_ptr_en =
561 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
562 uint64_t rxx_jabber =
563 cvmx_read_csr(CVMX_GMXX_RXX_JABBER
564 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
565 uint64_t frame_max =
566 cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX
567 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
568
569 /* Configure port to gig FDX as required for loopback mode */
570 cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT);
571
572 /*
573 * Disable reception on all ports so if traffic is present it
574 * will not interfere.
575 */
576 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0);
577
578 cvmx_wait(100000000ull);
579
580 for (retry_loop_cnt = 0; retry_loop_cnt < 10; retry_loop_cnt++) {
581 retry_cnt = 100000;
582 wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
583 pkt_pcnt = (wqe_pcnt >> 7) & 0x7f;
584 wqe_pcnt &= 0x7f;
585
586 num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3;
587
588 if (num_segs == 0)
589 goto fix_ipd_exit;
590
591 num_segs += 1;
592
593 size =
594 FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES +
595 ((num_segs - 1) * FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) -
596 (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2);
597
598 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)),
599 1 << INDEX(FIX_IPD_OUTPORT));
600 CVMX_SYNC;
601
602 g_buffer.u64 = 0;
603 g_buffer.s.addr =
604 cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL));
605 if (g_buffer.s.addr == 0) {
606 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
607 "buffer allocation failure.\n");
608 goto fix_ipd_exit;
609 }
610
611 g_buffer.s.pool = CVMX_FPA_WQE_POOL;
612 g_buffer.s.size = num_segs;
613
614 pkt_buffer.u64 = 0;
615 pkt_buffer.s.addr =
616 cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL));
617 if (pkt_buffer.s.addr == 0) {
618 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
619 "buffer allocation failure.\n");
620 goto fix_ipd_exit;
621 }
622 pkt_buffer.s.i = 1;
623 pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL;
624 pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES;
625
626 p64 = (uint64_t *) cvmx_phys_to_ptr(pkt_buffer.s.addr);
627 p64[0] = 0xffffffffffff0000ull;
628 p64[1] = 0x08004510ull;
629 p64[2] = ((uint64_t) (size - 14) << 48) | 0x5ae740004000ull;
630 p64[3] = 0x3a5fc0a81073c0a8ull;
631
632 for (i = 0; i < num_segs; i++) {
633 if (i > 0)
634 pkt_buffer.s.size =
635 FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES;
636
637 if (i == (num_segs - 1))
638 pkt_buffer.s.i = 0;
639
640 *(uint64_t *) cvmx_phys_to_ptr(g_buffer.s.addr +
641 8 * i) = pkt_buffer.u64;
642 }
643
644 /* Build the PKO command */
645 pko_command.u64 = 0;
646 pko_command.s.segs = num_segs;
647 pko_command.s.total_bytes = size;
648 pko_command.s.dontfree = 0;
649 pko_command.s.gather = 1;
650
651 gmx_cfg.u64 =
652 cvmx_read_csr(CVMX_GMXX_PRTX_CFG
653 (INDEX(FIX_IPD_OUTPORT),
654 INTERFACE(FIX_IPD_OUTPORT)));
655 gmx_cfg.s.en = 1;
656 cvmx_write_csr(CVMX_GMXX_PRTX_CFG
657 (INDEX(FIX_IPD_OUTPORT),
658 INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64);
659 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
660 1 << INDEX(FIX_IPD_OUTPORT));
661 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
662 1 << INDEX(FIX_IPD_OUTPORT));
663
664 cvmx_write_csr(CVMX_GMXX_RXX_JABBER
665 (INDEX(FIX_IPD_OUTPORT),
666 INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
667 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
668 (INDEX(FIX_IPD_OUTPORT),
669 INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
670
671 cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT,
672 cvmx_pko_get_base_queue
673 (FIX_IPD_OUTPORT),
674 CVMX_PKO_LOCK_CMD_QUEUE);
675 cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT,
676 cvmx_pko_get_base_queue
677 (FIX_IPD_OUTPORT), pko_command,
678 g_buffer, CVMX_PKO_LOCK_CMD_QUEUE);
679
680 CVMX_SYNC;
681
682 do {
683 work = cvmx_pow_work_request_sync(CVMX_POW_WAIT);
684 retry_cnt--;
685 } while ((work == NULL) && (retry_cnt > 0));
686
687 if (!retry_cnt)
688 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
689 "get_work() timeout occurred.\n");
690
691 /* Free packet */
692 if (work)
693 cvmx_helper_free_packet_data(work);
694 }
695
696fix_ipd_exit:
697
698 /* Return CSR configs to saved values */
699 cvmx_write_csr(CVMX_GMXX_PRTX_CFG
700 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
701 prtx_cfg);
702 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
703 tx_ptr_en);
704 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
705 rx_ptr_en);
706 cvmx_write_csr(CVMX_GMXX_RXX_JABBER
707 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
708 rxx_jabber);
709 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
710 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
711 frame_max);
712 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0);
713 /* Set link to down so autonegotiation will set it up again */
714 link_info.u64 = 0;
715 cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info);
716
717 /*
718 * Bring the link back up as autonegotiation is not done in
719 * user applications.
720 */
721 cvmx_helper_link_autoconf(FIX_IPD_OUTPORT);
722
723 CVMX_SYNC;
724 if (num_segs)
725 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n");
726
727 return !!num_segs;
728
729}
730
731/**
732 * Called after all internal packet IO paths are setup. This
733 * function enables IPD/PIP and begins packet input and output.
734 *
735 * Returns Zero on success, negative on failure
736 */
737int cvmx_helper_ipd_and_packet_input_enable(void)
738{
739 int num_interfaces;
740 int interface;
741
742 /* Enable IPD */
743 cvmx_ipd_enable();
744
745 /*
746 * Time to enable hardware ports packet input and output. Note
747 * that at this point IPD/PIP must be fully functional and PKO
748 * must be disabled
749 */
750 num_interfaces = cvmx_helper_get_number_of_interfaces();
751 for (interface = 0; interface < num_interfaces; interface++) {
752 if (cvmx_helper_ports_on_interface(interface) > 0)
753 __cvmx_helper_packet_hardware_enable(interface);
754 }
755
756 /* Finally enable PKO now that the entire path is up and running */
757 cvmx_pko_enable();
758
759 if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1)
760 || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1))
761 && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM))
762 __cvmx_helper_errata_fix_ipd_ptr_alignment();
763 return 0;
764}
765
766/**
767 * Initialize the PIP, IPD, and PKO hardware to support
768 * simple priority based queues for the ethernet ports. Each
769 * port is configured with a number of priority queues based
770 * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower
771 * priority than the previous.
772 *
773 * Returns Zero on success, non-zero on failure
774 */
775int cvmx_helper_initialize_packet_io_global(void)
776{
777 int result = 0;
778 int interface;
779 union cvmx_l2c_cfg l2c_cfg;
780 union cvmx_smix_en smix_en;
781 const int num_interfaces = cvmx_helper_get_number_of_interfaces();
782
783 /*
784 * CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to
785 * be disabled.
786 */
787 if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
788 __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1);
789
790 /*
791 * Tell L2 to give the IOB statically higher priority compared
792 * to the cores. This avoids conditions where IO blocks might
793 * be starved under very high L2 loads.
794 */
795 l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
796 l2c_cfg.s.lrf_arb_mode = 0;
797 l2c_cfg.s.rfb_arb_mode = 0;
798 cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64);
799
800 /* Make sure SMI/MDIO is enabled so we can query PHYs */
801 smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0));
802 if (!smix_en.s.en) {
803 smix_en.s.en = 1;
804 cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64);
805 }
806
807 /* Newer chips actually have two SMI/MDIO interfaces */
808 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) &&
809 !OCTEON_IS_MODEL(OCTEON_CN58XX) &&
810 !OCTEON_IS_MODEL(OCTEON_CN50XX)) {
811 smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1));
812 if (!smix_en.s.en) {
813 smix_en.s.en = 1;
814 cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64);
815 }
816 }
817
818 cvmx_pko_initialize_global();
819 for (interface = 0; interface < num_interfaces; interface++) {
820 result |= cvmx_helper_interface_probe(interface);
821 if (cvmx_helper_ports_on_interface(interface) > 0)
822 cvmx_dprintf("Interface %d has %d ports (%s)\n",
823 interface,
824 cvmx_helper_ports_on_interface(interface),
825 cvmx_helper_interface_mode_to_string
826 (cvmx_helper_interface_get_mode
827 (interface)));
828 result |= __cvmx_helper_interface_setup_ipd(interface);
829 result |= __cvmx_helper_interface_setup_pko(interface);
830 }
831
832 result |= __cvmx_helper_global_setup_ipd();
833 result |= __cvmx_helper_global_setup_pko();
834
835 /* Enable any flow control and backpressure */
836 result |= __cvmx_helper_global_setup_backpressure();
837
838#if CVMX_HELPER_ENABLE_IPD
839 result |= cvmx_helper_ipd_and_packet_input_enable();
840#endif
841 return result;
842}
843
844/**
845 * Does core local initialization for packet io
846 *
847 * Returns Zero on success, non-zero on failure
848 */
849int cvmx_helper_initialize_packet_io_local(void)
850{
851 return cvmx_pko_initialize_local();
852}
853
854/**
855 * Auto configure an IPD/PKO port link state and speed. This
856 * function basically does the equivalent of:
857 * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
858 *
859 * @ipd_port: IPD/PKO port to auto configure
860 *
861 * Returns Link state after configure
862 */
863cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
864{
865 cvmx_helper_link_info_t link_info;
866 int interface = cvmx_helper_get_interface_num(ipd_port);
867 int index = cvmx_helper_get_interface_index_num(ipd_port);
868
869 if (index >= cvmx_helper_ports_on_interface(interface)) {
870 link_info.u64 = 0;
871 return link_info;
872 }
873
874 link_info = cvmx_helper_link_get(ipd_port);
875 if (link_info.u64 == port_link_info[ipd_port].u64)
876 return link_info;
877
878 /* If we fail to set the link speed, port_link_info will not change */
879 cvmx_helper_link_set(ipd_port, link_info);
880
881 /*
882 * port_link_info should be the current value, which will be
883 * different than expect if cvmx_helper_link_set() failed.
884 */
885 return port_link_info[ipd_port];
886}
887
888/**
889 * Return the link state of an IPD/PKO port as returned by
890 * auto negotiation. The result of this function may not match
891 * Octeon's link config if auto negotiation has changed since
892 * the last call to cvmx_helper_link_set().
893 *
894 * @ipd_port: IPD/PKO port to query
895 *
896 * Returns Link state
897 */
898cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
899{
900 cvmx_helper_link_info_t result;
901 int interface = cvmx_helper_get_interface_num(ipd_port);
902 int index = cvmx_helper_get_interface_index_num(ipd_port);
903
904 /* The default result will be a down link unless the code below
905 changes it */
906 result.u64 = 0;
907
908 if (index >= cvmx_helper_ports_on_interface(interface))
909 return result;
910
911 switch (cvmx_helper_interface_get_mode(interface)) {
912 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
913 case CVMX_HELPER_INTERFACE_MODE_PCIE:
914 /* Network links are not supported */
915 break;
916 case CVMX_HELPER_INTERFACE_MODE_XAUI:
917 result = __cvmx_helper_xaui_link_get(ipd_port);
918 break;
919 case CVMX_HELPER_INTERFACE_MODE_GMII:
920 if (index == 0)
921 result = __cvmx_helper_rgmii_link_get(ipd_port);
922 else {
923 result.s.full_duplex = 1;
924 result.s.link_up = 1;
925 result.s.speed = 1000;
926 }
927 break;
928 case CVMX_HELPER_INTERFACE_MODE_RGMII:
929 result = __cvmx_helper_rgmii_link_get(ipd_port);
930 break;
931 case CVMX_HELPER_INTERFACE_MODE_SPI:
932 result = __cvmx_helper_spi_link_get(ipd_port);
933 break;
934 case CVMX_HELPER_INTERFACE_MODE_SGMII:
935 case CVMX_HELPER_INTERFACE_MODE_PICMG:
936 result = __cvmx_helper_sgmii_link_get(ipd_port);
937 break;
938 case CVMX_HELPER_INTERFACE_MODE_NPI:
939 case CVMX_HELPER_INTERFACE_MODE_LOOP:
940 /* Network links are not supported */
941 break;
942 }
943 return result;
944}
945
946/**
947 * Configure an IPD/PKO port for the specified link state. This
948 * function does not influence auto negotiation at the PHY level.
949 * The passed link state must always match the link state returned
950 * by cvmx_helper_link_get(). It is normally best to use
951 * cvmx_helper_link_autoconf() instead.
952 *
953 * @ipd_port: IPD/PKO port to configure
954 * @link_info: The new link state
955 *
956 * Returns Zero on success, negative on failure
957 */
958int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
959{
960 int result = -1;
961 int interface = cvmx_helper_get_interface_num(ipd_port);
962 int index = cvmx_helper_get_interface_index_num(ipd_port);
963
964 if (index >= cvmx_helper_ports_on_interface(interface))
965 return -1;
966
967 switch (cvmx_helper_interface_get_mode(interface)) {
968 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
969 case CVMX_HELPER_INTERFACE_MODE_PCIE:
970 break;
971 case CVMX_HELPER_INTERFACE_MODE_XAUI:
972 result = __cvmx_helper_xaui_link_set(ipd_port, link_info);
973 break;
974 /*
975 * RGMII/GMII/MII are all treated about the same. Most
976 * functions refer to these ports as RGMII.
977 */
978 case CVMX_HELPER_INTERFACE_MODE_RGMII:
979 case CVMX_HELPER_INTERFACE_MODE_GMII:
980 result = __cvmx_helper_rgmii_link_set(ipd_port, link_info);
981 break;
982 case CVMX_HELPER_INTERFACE_MODE_SPI:
983 result = __cvmx_helper_spi_link_set(ipd_port, link_info);
984 break;
985 case CVMX_HELPER_INTERFACE_MODE_SGMII:
986 case CVMX_HELPER_INTERFACE_MODE_PICMG:
987 result = __cvmx_helper_sgmii_link_set(ipd_port, link_info);
988 break;
989 case CVMX_HELPER_INTERFACE_MODE_NPI:
990 case CVMX_HELPER_INTERFACE_MODE_LOOP:
991 break;
992 }
993 /* Set the port_link_info here so that the link status is updated
994 no matter how cvmx_helper_link_set is called. We don't change
995 the value if link_set failed */
996 if (result == 0)
997 port_link_info[ipd_port].u64 = link_info.u64;
998 return result;
999}
1000
1001/**
1002 * Configure a port for internal and/or external loopback. Internal loopback
1003 * causes packets sent by the port to be received by Octeon. External loopback
1004 * causes packets received from the wire to sent out again.
1005 *
1006 * @ipd_port: IPD/PKO port to loopback.
1007 * @enable_internal:
1008 * Non zero if you want internal loopback
1009 * @enable_external:
1010 * Non zero if you want external loopback
1011 *
1012 * Returns Zero on success, negative on failure.
1013 */
1014int cvmx_helper_configure_loopback(int ipd_port, int enable_internal,
1015 int enable_external)
1016{
1017 int result = -1;
1018 int interface = cvmx_helper_get_interface_num(ipd_port);
1019 int index = cvmx_helper_get_interface_index_num(ipd_port);
1020
1021 if (index >= cvmx_helper_ports_on_interface(interface))
1022 return -1;
1023
1024 switch (cvmx_helper_interface_get_mode(interface)) {
1025 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1026 case CVMX_HELPER_INTERFACE_MODE_PCIE:
1027 case CVMX_HELPER_INTERFACE_MODE_SPI:
1028 case CVMX_HELPER_INTERFACE_MODE_NPI:
1029 case CVMX_HELPER_INTERFACE_MODE_LOOP:
1030 break;
1031 case CVMX_HELPER_INTERFACE_MODE_XAUI:
1032 result =
1033 __cvmx_helper_xaui_configure_loopback(ipd_port,
1034 enable_internal,
1035 enable_external);
1036 break;
1037 case CVMX_HELPER_INTERFACE_MODE_RGMII:
1038 case CVMX_HELPER_INTERFACE_MODE_GMII:
1039 result =
1040 __cvmx_helper_rgmii_configure_loopback(ipd_port,
1041 enable_internal,
1042 enable_external);
1043 break;
1044 case CVMX_HELPER_INTERFACE_MODE_SGMII:
1045 case CVMX_HELPER_INTERFACE_MODE_PICMG:
1046 result =
1047 __cvmx_helper_sgmii_configure_loopback(ipd_port,
1048 enable_internal,
1049 enable_external);
1050 break;
1051 }
1052 return result;
1053}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c b/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c
new file mode 100644
index 000000000000..e59d1b79f24c
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-interrupt-decodes.c
@@ -0,0 +1,371 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2009 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 *
30 * Automatically generated functions useful for enabling
31 * and decoding RSL_INT_BLOCKS interrupts.
32 *
33 */
34
35#include <asm/octeon/octeon.h>
36
37#include <asm/octeon/cvmx-gmxx-defs.h>
38#include <asm/octeon/cvmx-pcsx-defs.h>
39#include <asm/octeon/cvmx-pcsxx-defs.h>
40#include <asm/octeon/cvmx-spxx-defs.h>
41#include <asm/octeon/cvmx-stxx-defs.h>
42
43#ifndef PRINT_ERROR
44#define PRINT_ERROR(format, ...)
45#endif
46
47
48/**
49 * __cvmx_interrupt_gmxx_rxx_int_en_enable enables all interrupt bits in cvmx_gmxx_rxx_int_en_t
50 */
51void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block)
52{
53 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
54 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(index, block),
55 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(index, block)));
56 gmx_rx_int_en.u64 = 0;
57 if (OCTEON_IS_MODEL(OCTEON_CN56XX)) {
58 /* Skipping gmx_rx_int_en.s.reserved_29_63 */
59 gmx_rx_int_en.s.hg2cc = 1;
60 gmx_rx_int_en.s.hg2fld = 1;
61 gmx_rx_int_en.s.undat = 1;
62 gmx_rx_int_en.s.uneop = 1;
63 gmx_rx_int_en.s.unsop = 1;
64 gmx_rx_int_en.s.bad_term = 1;
65 gmx_rx_int_en.s.bad_seq = 1;
66 gmx_rx_int_en.s.rem_fault = 1;
67 gmx_rx_int_en.s.loc_fault = 1;
68 gmx_rx_int_en.s.pause_drp = 1;
69 /* Skipping gmx_rx_int_en.s.reserved_16_18 */
70 /*gmx_rx_int_en.s.ifgerr = 1; */
71 /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
72 /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
73 /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
74 /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
75 gmx_rx_int_en.s.ovrerr = 1;
76 /* Skipping gmx_rx_int_en.s.reserved_9_9 */
77 gmx_rx_int_en.s.skperr = 1;
78 gmx_rx_int_en.s.rcverr = 1;
79 /* Skipping gmx_rx_int_en.s.reserved_5_6 */
80 /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */
81 gmx_rx_int_en.s.jabber = 1;
82 /* Skipping gmx_rx_int_en.s.reserved_2_2 */
83 gmx_rx_int_en.s.carext = 1;
84 /* Skipping gmx_rx_int_en.s.reserved_0_0 */
85 }
86 if (OCTEON_IS_MODEL(OCTEON_CN30XX)) {
87 /* Skipping gmx_rx_int_en.s.reserved_19_63 */
88 /*gmx_rx_int_en.s.phy_dupx = 1; */
89 /*gmx_rx_int_en.s.phy_spd = 1; */
90 /*gmx_rx_int_en.s.phy_link = 1; */
91 /*gmx_rx_int_en.s.ifgerr = 1; */
92 /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
93 /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
94 /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
95 /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
96 gmx_rx_int_en.s.ovrerr = 1;
97 gmx_rx_int_en.s.niberr = 1;
98 gmx_rx_int_en.s.skperr = 1;
99 gmx_rx_int_en.s.rcverr = 1;
100 /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */
101 gmx_rx_int_en.s.alnerr = 1;
102 /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */
103 gmx_rx_int_en.s.jabber = 1;
104 gmx_rx_int_en.s.maxerr = 1;
105 gmx_rx_int_en.s.carext = 1;
106 gmx_rx_int_en.s.minerr = 1;
107 }
108 if (OCTEON_IS_MODEL(OCTEON_CN50XX)) {
109 /* Skipping gmx_rx_int_en.s.reserved_20_63 */
110 gmx_rx_int_en.s.pause_drp = 1;
111 /*gmx_rx_int_en.s.phy_dupx = 1; */
112 /*gmx_rx_int_en.s.phy_spd = 1; */
113 /*gmx_rx_int_en.s.phy_link = 1; */
114 /*gmx_rx_int_en.s.ifgerr = 1; */
115 /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
116 /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
117 /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
118 /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
119 gmx_rx_int_en.s.ovrerr = 1;
120 gmx_rx_int_en.s.niberr = 1;
121 gmx_rx_int_en.s.skperr = 1;
122 gmx_rx_int_en.s.rcverr = 1;
123 /* Skipping gmx_rx_int_en.s.reserved_6_6 */
124 gmx_rx_int_en.s.alnerr = 1;
125 /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */
126 gmx_rx_int_en.s.jabber = 1;
127 /* Skipping gmx_rx_int_en.s.reserved_2_2 */
128 gmx_rx_int_en.s.carext = 1;
129 /* Skipping gmx_rx_int_en.s.reserved_0_0 */
130 }
131 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
132 /* Skipping gmx_rx_int_en.s.reserved_19_63 */
133 /*gmx_rx_int_en.s.phy_dupx = 1; */
134 /*gmx_rx_int_en.s.phy_spd = 1; */
135 /*gmx_rx_int_en.s.phy_link = 1; */
136 /*gmx_rx_int_en.s.ifgerr = 1; */
137 /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
138 /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
139 /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
140 /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
141 gmx_rx_int_en.s.ovrerr = 1;
142 gmx_rx_int_en.s.niberr = 1;
143 gmx_rx_int_en.s.skperr = 1;
144 gmx_rx_int_en.s.rcverr = 1;
145 /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */
146 gmx_rx_int_en.s.alnerr = 1;
147 /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */
148 gmx_rx_int_en.s.jabber = 1;
149 gmx_rx_int_en.s.maxerr = 1;
150 gmx_rx_int_en.s.carext = 1;
151 gmx_rx_int_en.s.minerr = 1;
152 }
153 if (OCTEON_IS_MODEL(OCTEON_CN31XX)) {
154 /* Skipping gmx_rx_int_en.s.reserved_19_63 */
155 /*gmx_rx_int_en.s.phy_dupx = 1; */
156 /*gmx_rx_int_en.s.phy_spd = 1; */
157 /*gmx_rx_int_en.s.phy_link = 1; */
158 /*gmx_rx_int_en.s.ifgerr = 1; */
159 /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
160 /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
161 /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
162 /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
163 gmx_rx_int_en.s.ovrerr = 1;
164 gmx_rx_int_en.s.niberr = 1;
165 gmx_rx_int_en.s.skperr = 1;
166 gmx_rx_int_en.s.rcverr = 1;
167 /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */
168 gmx_rx_int_en.s.alnerr = 1;
169 /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */
170 gmx_rx_int_en.s.jabber = 1;
171 gmx_rx_int_en.s.maxerr = 1;
172 gmx_rx_int_en.s.carext = 1;
173 gmx_rx_int_en.s.minerr = 1;
174 }
175 if (OCTEON_IS_MODEL(OCTEON_CN58XX)) {
176 /* Skipping gmx_rx_int_en.s.reserved_20_63 */
177 gmx_rx_int_en.s.pause_drp = 1;
178 /*gmx_rx_int_en.s.phy_dupx = 1; */
179 /*gmx_rx_int_en.s.phy_spd = 1; */
180 /*gmx_rx_int_en.s.phy_link = 1; */
181 /*gmx_rx_int_en.s.ifgerr = 1; */
182 /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
183 /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
184 /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
185 /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
186 gmx_rx_int_en.s.ovrerr = 1;
187 gmx_rx_int_en.s.niberr = 1;
188 gmx_rx_int_en.s.skperr = 1;
189 gmx_rx_int_en.s.rcverr = 1;
190 /*gmx_rx_int_en.s.lenerr = 1; // Length errors are handled when we get work */
191 gmx_rx_int_en.s.alnerr = 1;
192 /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */
193 gmx_rx_int_en.s.jabber = 1;
194 gmx_rx_int_en.s.maxerr = 1;
195 gmx_rx_int_en.s.carext = 1;
196 gmx_rx_int_en.s.minerr = 1;
197 }
198 if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
199 /* Skipping gmx_rx_int_en.s.reserved_29_63 */
200 gmx_rx_int_en.s.hg2cc = 1;
201 gmx_rx_int_en.s.hg2fld = 1;
202 gmx_rx_int_en.s.undat = 1;
203 gmx_rx_int_en.s.uneop = 1;
204 gmx_rx_int_en.s.unsop = 1;
205 gmx_rx_int_en.s.bad_term = 1;
206 gmx_rx_int_en.s.bad_seq = 0;
207 gmx_rx_int_en.s.rem_fault = 1;
208 gmx_rx_int_en.s.loc_fault = 0;
209 gmx_rx_int_en.s.pause_drp = 1;
210 /* Skipping gmx_rx_int_en.s.reserved_16_18 */
211 /*gmx_rx_int_en.s.ifgerr = 1; */
212 /*gmx_rx_int_en.s.coldet = 1; // Collsion detect */
213 /*gmx_rx_int_en.s.falerr = 1; // False carrier error or extend error after slottime */
214 /*gmx_rx_int_en.s.rsverr = 1; // RGMII reserved opcodes */
215 /*gmx_rx_int_en.s.pcterr = 1; // Bad Preamble / Protocol */
216 gmx_rx_int_en.s.ovrerr = 1;
217 /* Skipping gmx_rx_int_en.s.reserved_9_9 */
218 gmx_rx_int_en.s.skperr = 1;
219 gmx_rx_int_en.s.rcverr = 1;
220 /* Skipping gmx_rx_int_en.s.reserved_5_6 */
221 /*gmx_rx_int_en.s.fcserr = 1; // FCS errors are handled when we get work */
222 gmx_rx_int_en.s.jabber = 1;
223 /* Skipping gmx_rx_int_en.s.reserved_2_2 */
224 gmx_rx_int_en.s.carext = 1;
225 /* Skipping gmx_rx_int_en.s.reserved_0_0 */
226 }
227 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(index, block), gmx_rx_int_en.u64);
228}
229/**
230 * __cvmx_interrupt_pcsx_intx_en_reg_enable enables all interrupt bits in cvmx_pcsx_intx_en_reg_t
231 */
232void __cvmx_interrupt_pcsx_intx_en_reg_enable(int index, int block)
233{
234 union cvmx_pcsx_intx_en_reg pcs_int_en_reg;
235 cvmx_write_csr(CVMX_PCSX_INTX_REG(index, block),
236 cvmx_read_csr(CVMX_PCSX_INTX_REG(index, block)));
237 pcs_int_en_reg.u64 = 0;
238 if (OCTEON_IS_MODEL(OCTEON_CN56XX)) {
239 /* Skipping pcs_int_en_reg.s.reserved_12_63 */
240 /*pcs_int_en_reg.s.dup = 1; // This happens during normal operation */
241 pcs_int_en_reg.s.sync_bad_en = 1;
242 pcs_int_en_reg.s.an_bad_en = 1;
243 pcs_int_en_reg.s.rxlock_en = 1;
244 pcs_int_en_reg.s.rxbad_en = 1;
245 /*pcs_int_en_reg.s.rxerr_en = 1; // This happens during normal operation */
246 pcs_int_en_reg.s.txbad_en = 1;
247 pcs_int_en_reg.s.txfifo_en = 1;
248 pcs_int_en_reg.s.txfifu_en = 1;
249 pcs_int_en_reg.s.an_err_en = 1;
250 /*pcs_int_en_reg.s.xmit_en = 1; // This happens during normal operation */
251 /*pcs_int_en_reg.s.lnkspd_en = 1; // This happens during normal operation */
252 }
253 if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
254 /* Skipping pcs_int_en_reg.s.reserved_12_63 */
255 /*pcs_int_en_reg.s.dup = 1; // This happens during normal operation */
256 pcs_int_en_reg.s.sync_bad_en = 1;
257 pcs_int_en_reg.s.an_bad_en = 1;
258 pcs_int_en_reg.s.rxlock_en = 1;
259 pcs_int_en_reg.s.rxbad_en = 1;
260 /*pcs_int_en_reg.s.rxerr_en = 1; // This happens during normal operation */
261 pcs_int_en_reg.s.txbad_en = 1;
262 pcs_int_en_reg.s.txfifo_en = 1;
263 pcs_int_en_reg.s.txfifu_en = 1;
264 pcs_int_en_reg.s.an_err_en = 1;
265 /*pcs_int_en_reg.s.xmit_en = 1; // This happens during normal operation */
266 /*pcs_int_en_reg.s.lnkspd_en = 1; // This happens during normal operation */
267 }
268 cvmx_write_csr(CVMX_PCSX_INTX_EN_REG(index, block), pcs_int_en_reg.u64);
269}
270/**
271 * __cvmx_interrupt_pcsxx_int_en_reg_enable enables all interrupt bits in cvmx_pcsxx_int_en_reg_t
272 */
273void __cvmx_interrupt_pcsxx_int_en_reg_enable(int index)
274{
275 union cvmx_pcsxx_int_en_reg pcsx_int_en_reg;
276 cvmx_write_csr(CVMX_PCSXX_INT_REG(index),
277 cvmx_read_csr(CVMX_PCSXX_INT_REG(index)));
278 pcsx_int_en_reg.u64 = 0;
279 if (OCTEON_IS_MODEL(OCTEON_CN56XX)) {
280 /* Skipping pcsx_int_en_reg.s.reserved_6_63 */
281 pcsx_int_en_reg.s.algnlos_en = 1;
282 pcsx_int_en_reg.s.synlos_en = 1;
283 pcsx_int_en_reg.s.bitlckls_en = 1;
284 pcsx_int_en_reg.s.rxsynbad_en = 1;
285 pcsx_int_en_reg.s.rxbad_en = 1;
286 pcsx_int_en_reg.s.txflt_en = 1;
287 }
288 if (OCTEON_IS_MODEL(OCTEON_CN52XX)) {
289 /* Skipping pcsx_int_en_reg.s.reserved_6_63 */
290 pcsx_int_en_reg.s.algnlos_en = 1;
291 pcsx_int_en_reg.s.synlos_en = 1;
292 pcsx_int_en_reg.s.bitlckls_en = 0; /* Happens if XAUI module is not installed */
293 pcsx_int_en_reg.s.rxsynbad_en = 1;
294 pcsx_int_en_reg.s.rxbad_en = 1;
295 pcsx_int_en_reg.s.txflt_en = 1;
296 }
297 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(index), pcsx_int_en_reg.u64);
298}
299
300/**
301 * __cvmx_interrupt_spxx_int_msk_enable enables all interrupt bits in cvmx_spxx_int_msk_t
302 */
303void __cvmx_interrupt_spxx_int_msk_enable(int index)
304{
305 union cvmx_spxx_int_msk spx_int_msk;
306 cvmx_write_csr(CVMX_SPXX_INT_REG(index),
307 cvmx_read_csr(CVMX_SPXX_INT_REG(index)));
308 spx_int_msk.u64 = 0;
309 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
310 /* Skipping spx_int_msk.s.reserved_12_63 */
311 spx_int_msk.s.calerr = 1;
312 spx_int_msk.s.syncerr = 1;
313 spx_int_msk.s.diperr = 1;
314 spx_int_msk.s.tpaovr = 1;
315 spx_int_msk.s.rsverr = 1;
316 spx_int_msk.s.drwnng = 1;
317 spx_int_msk.s.clserr = 1;
318 spx_int_msk.s.spiovr = 1;
319 /* Skipping spx_int_msk.s.reserved_2_3 */
320 spx_int_msk.s.abnorm = 1;
321 spx_int_msk.s.prtnxa = 1;
322 }
323 if (OCTEON_IS_MODEL(OCTEON_CN58XX)) {
324 /* Skipping spx_int_msk.s.reserved_12_63 */
325 spx_int_msk.s.calerr = 1;
326 spx_int_msk.s.syncerr = 1;
327 spx_int_msk.s.diperr = 1;
328 spx_int_msk.s.tpaovr = 1;
329 spx_int_msk.s.rsverr = 1;
330 spx_int_msk.s.drwnng = 1;
331 spx_int_msk.s.clserr = 1;
332 spx_int_msk.s.spiovr = 1;
333 /* Skipping spx_int_msk.s.reserved_2_3 */
334 spx_int_msk.s.abnorm = 1;
335 spx_int_msk.s.prtnxa = 1;
336 }
337 cvmx_write_csr(CVMX_SPXX_INT_MSK(index), spx_int_msk.u64);
338}
339/**
340 * __cvmx_interrupt_stxx_int_msk_enable enables all interrupt bits in cvmx_stxx_int_msk_t
341 */
342void __cvmx_interrupt_stxx_int_msk_enable(int index)
343{
344 union cvmx_stxx_int_msk stx_int_msk;
345 cvmx_write_csr(CVMX_STXX_INT_REG(index),
346 cvmx_read_csr(CVMX_STXX_INT_REG(index)));
347 stx_int_msk.u64 = 0;
348 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
349 /* Skipping stx_int_msk.s.reserved_8_63 */
350 stx_int_msk.s.frmerr = 1;
351 stx_int_msk.s.unxfrm = 1;
352 stx_int_msk.s.nosync = 1;
353 stx_int_msk.s.diperr = 1;
354 stx_int_msk.s.datovr = 1;
355 stx_int_msk.s.ovrbst = 1;
356 stx_int_msk.s.calpar1 = 1;
357 stx_int_msk.s.calpar0 = 1;
358 }
359 if (OCTEON_IS_MODEL(OCTEON_CN58XX)) {
360 /* Skipping stx_int_msk.s.reserved_8_63 */
361 stx_int_msk.s.frmerr = 1;
362 stx_int_msk.s.unxfrm = 1;
363 stx_int_msk.s.nosync = 1;
364 stx_int_msk.s.diperr = 1;
365 stx_int_msk.s.datovr = 1;
366 stx_int_msk.s.ovrbst = 1;
367 stx_int_msk.s.calpar1 = 1;
368 stx_int_msk.s.calpar0 = 1;
369 }
370 cvmx_write_csr(CVMX_STXX_INT_MSK(index), stx_int_msk.u64);
371}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c b/arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c
new file mode 100644
index 000000000000..bea7538ea4e9
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-interrupt-rsl.c
@@ -0,0 +1,140 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Utility functions to decode Octeon's RSL_INT_BLOCKS
30 * interrupts into error messages.
31 */
32
33#include <asm/octeon/octeon.h>
34
35#include <asm/octeon/cvmx-asxx-defs.h>
36#include <asm/octeon/cvmx-gmxx-defs.h>
37
38#ifndef PRINT_ERROR
39#define PRINT_ERROR(format, ...)
40#endif
41
42void __cvmx_interrupt_gmxx_rxx_int_en_enable(int index, int block);
43
44/**
45 * Enable ASX error interrupts that exist on CN3XXX, CN50XX, and
46 * CN58XX.
47 *
48 * @block: Interface to enable 0-1
49 */
50void __cvmx_interrupt_asxx_enable(int block)
51{
52 int mask;
53 union cvmx_asxx_int_en csr;
54 /*
55 * CN38XX and CN58XX have two interfaces with 4 ports per
56 * interface. All other chips have a max of 3 ports on
57 * interface 0
58 */
59 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX))
60 mask = 0xf; /* Set enables for 4 ports */
61 else
62 mask = 0x7; /* Set enables for 3 ports */
63
64 /* Enable interface interrupts */
65 csr.u64 = cvmx_read_csr(CVMX_ASXX_INT_EN(block));
66 csr.s.txpsh = mask;
67 csr.s.txpop = mask;
68 csr.s.ovrflw = mask;
69 cvmx_write_csr(CVMX_ASXX_INT_EN(block), csr.u64);
70}
71/**
72 * Enable GMX error reporting for the supplied interface
73 *
74 * @interface: Interface to enable
75 */
76void __cvmx_interrupt_gmxx_enable(int interface)
77{
78 union cvmx_gmxx_inf_mode mode;
79 union cvmx_gmxx_tx_int_en gmx_tx_int_en;
80 int num_ports;
81 int index;
82
83 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
84
85 if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
86 if (mode.s.en) {
87 switch (mode.cn56xx.mode) {
88 case 1: /* XAUI */
89 num_ports = 1;
90 break;
91 case 2: /* SGMII */
92 case 3: /* PICMG */
93 num_ports = 4;
94 break;
95 default: /* Disabled */
96 num_ports = 0;
97 break;
98 }
99 } else
100 num_ports = 0;
101 } else {
102 if (mode.s.en) {
103 if (OCTEON_IS_MODEL(OCTEON_CN38XX)
104 || OCTEON_IS_MODEL(OCTEON_CN58XX)) {
105 /*
106 * SPI on CN38XX and CN58XX report all
107 * errors through port 0. RGMII needs
108 * to check all 4 ports
109 */
110 if (mode.s.type)
111 num_ports = 1;
112 else
113 num_ports = 4;
114 } else {
115 /*
116 * CN30XX, CN31XX, and CN50XX have two
117 * or three ports. GMII and MII has 2,
118 * RGMII has three
119 */
120 if (mode.s.type)
121 num_ports = 2;
122 else
123 num_ports = 3;
124 }
125 } else
126 num_ports = 0;
127 }
128
129 gmx_tx_int_en.u64 = 0;
130 if (num_ports) {
131 if (OCTEON_IS_MODEL(OCTEON_CN38XX)
132 || OCTEON_IS_MODEL(OCTEON_CN58XX))
133 gmx_tx_int_en.s.ncb_nxa = 1;
134 gmx_tx_int_en.s.pko_nxa = 1;
135 }
136 gmx_tx_int_en.s.undflw = (1 << num_ports) - 1;
137 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64);
138 for (index = 0; index < num_ports; index++)
139 __cvmx_interrupt_gmxx_rxx_int_en_enable(index, interface);
140}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c
new file mode 100644
index 000000000000..f557084b1092
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c
@@ -0,0 +1,506 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 * Support library for the hardware Packet Output unit.
30 */
31
32#include <asm/octeon/octeon.h>
33
34#include <asm/octeon/cvmx-config.h>
35#include <asm/octeon/cvmx-pko.h>
36#include <asm/octeon/cvmx-helper.h>
37
38/**
39 * Internal state of packet output
40 */
41
42/**
43 * Call before any other calls to initialize the packet
44 * output system. This does chip global config, and should only be
45 * done by one core.
46 */
47
48void cvmx_pko_initialize_global(void)
49{
50 int i;
51 uint64_t priority = 8;
52 union cvmx_pko_reg_cmd_buf config;
53
54 /*
55 * Set the size of the PKO command buffers to an odd number of
56 * 64bit words. This allows the normal two word send to stay
57 * aligned and never span a comamnd word buffer.
58 */
59 config.u64 = 0;
60 config.s.pool = CVMX_FPA_OUTPUT_BUFFER_POOL;
61 config.s.size = CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE / 8 - 1;
62
63 cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64);
64
65 for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++)
66 cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1,
67 &priority);
68
69 /*
70 * If we aren't using all of the queues optimize PKO's
71 * internal memory.
72 */
73 if (OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)
74 || OCTEON_IS_MODEL(OCTEON_CN56XX)
75 || OCTEON_IS_MODEL(OCTEON_CN52XX)) {
76 int num_interfaces = cvmx_helper_get_number_of_interfaces();
77 int last_port =
78 cvmx_helper_get_last_ipd_port(num_interfaces - 1);
79 int max_queues =
80 cvmx_pko_get_base_queue(last_port) +
81 cvmx_pko_get_num_queues(last_port);
82 if (OCTEON_IS_MODEL(OCTEON_CN38XX)) {
83 if (max_queues <= 32)
84 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
85 else if (max_queues <= 64)
86 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
87 } else {
88 if (max_queues <= 64)
89 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 2);
90 else if (max_queues <= 128)
91 cvmx_write_csr(CVMX_PKO_REG_QUEUE_MODE, 1);
92 }
93 }
94}
95
96/**
97 * This function does per-core initialization required by the PKO routines.
98 * This must be called on all cores that will do packet output, and must
99 * be called after the FPA has been initialized and filled with pages.
100 *
101 * Returns 0 on success
102 * !0 on failure
103 */
104int cvmx_pko_initialize_local(void)
105{
106 /* Nothing to do */
107 return 0;
108}
109
110/**
111 * Enables the packet output hardware. It must already be
112 * configured.
113 */
114void cvmx_pko_enable(void)
115{
116 union cvmx_pko_reg_flags flags;
117
118 flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
119 if (flags.s.ena_pko)
120 cvmx_dprintf
121 ("Warning: Enabling PKO when PKO already enabled.\n");
122
123 flags.s.ena_dwb = 1;
124 flags.s.ena_pko = 1;
125 /*
126 * always enable big endian for 3-word command. Does nothing
127 * for 2-word.
128 */
129 flags.s.store_be = 1;
130 cvmx_write_csr(CVMX_PKO_REG_FLAGS, flags.u64);
131}
132
133/**
134 * Disables the packet output. Does not affect any configuration.
135 */
136void cvmx_pko_disable(void)
137{
138 union cvmx_pko_reg_flags pko_reg_flags;
139 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
140 pko_reg_flags.s.ena_pko = 0;
141 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
142}
143
144
145/**
146 * Reset the packet output.
147 */
148static void __cvmx_pko_reset(void)
149{
150 union cvmx_pko_reg_flags pko_reg_flags;
151 pko_reg_flags.u64 = cvmx_read_csr(CVMX_PKO_REG_FLAGS);
152 pko_reg_flags.s.reset = 1;
153 cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
154}
155
156/**
157 * Shutdown and free resources required by packet output.
158 */
159void cvmx_pko_shutdown(void)
160{
161 union cvmx_pko_mem_queue_ptrs config;
162 int queue;
163
164 cvmx_pko_disable();
165
166 for (queue = 0; queue < CVMX_PKO_MAX_OUTPUT_QUEUES; queue++) {
167 config.u64 = 0;
168 config.s.tail = 1;
169 config.s.index = 0;
170 config.s.port = CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID;
171 config.s.queue = queue & 0x7f;
172 config.s.qos_mask = 0;
173 config.s.buf_ptr = 0;
174 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX)) {
175 union cvmx_pko_reg_queue_ptrs1 config1;
176 config1.u64 = 0;
177 config1.s.qid7 = queue >> 7;
178 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
179 }
180 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
181 cvmx_cmd_queue_shutdown(CVMX_CMD_QUEUE_PKO(queue));
182 }
183 __cvmx_pko_reset();
184}
185
186/**
187 * Configure a output port and the associated queues for use.
188 *
189 * @port: Port to configure.
190 * @base_queue: First queue number to associate with this port.
191 * @num_queues: Number of queues to associate with this port
192 * @priority: Array of priority levels for each queue. Values are
193 * allowed to be 0-8. A value of 8 get 8 times the traffic
194 * of a value of 1. A value of 0 indicates that no rounds
195 * will be participated in. These priorities can be changed
196 * on the fly while the pko is enabled. A priority of 9
197 * indicates that static priority should be used. If static
198 * priority is used all queues with static priority must be
199 * contiguous starting at the base_queue, and lower numbered
200 * queues have higher priority than higher numbered queues.
201 * There must be num_queues elements in the array.
202 */
203cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue,
204 uint64_t num_queues,
205 const uint64_t priority[])
206{
207 cvmx_pko_status_t result_code;
208 uint64_t queue;
209 union cvmx_pko_mem_queue_ptrs config;
210 union cvmx_pko_reg_queue_ptrs1 config1;
211 int static_priority_base = -1;
212 int static_priority_end = -1;
213
214 if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS)
215 && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) {
216 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n",
217 (unsigned long long)port);
218 return CVMX_PKO_INVALID_PORT;
219 }
220
221 if (base_queue + num_queues > CVMX_PKO_MAX_OUTPUT_QUEUES) {
222 cvmx_dprintf
223 ("ERROR: cvmx_pko_config_port: Invalid queue range %llu\n",
224 (unsigned long long)(base_queue + num_queues));
225 return CVMX_PKO_INVALID_QUEUE;
226 }
227
228 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) {
229 /*
230 * Validate the static queue priority setup and set
231 * static_priority_base and static_priority_end
232 * accordingly.
233 */
234 for (queue = 0; queue < num_queues; queue++) {
235 /* Find first queue of static priority */
236 if (static_priority_base == -1
237 && priority[queue] ==
238 CVMX_PKO_QUEUE_STATIC_PRIORITY)
239 static_priority_base = queue;
240 /* Find last queue of static priority */
241 if (static_priority_base != -1
242 && static_priority_end == -1
243 && priority[queue] != CVMX_PKO_QUEUE_STATIC_PRIORITY
244 && queue)
245 static_priority_end = queue - 1;
246 else if (static_priority_base != -1
247 && static_priority_end == -1
248 && queue == num_queues - 1)
249 /* all queues are static priority */
250 static_priority_end = queue;
251 /*
252 * Check to make sure all static priority
253 * queues are contiguous. Also catches some
254 * cases of static priorites not starting at
255 * queue 0.
256 */
257 if (static_priority_end != -1
258 && (int)queue > static_priority_end
259 && priority[queue] ==
260 CVMX_PKO_QUEUE_STATIC_PRIORITY) {
261 cvmx_dprintf("ERROR: cvmx_pko_config_port: "
262 "Static priority queues aren't "
263 "contiguous or don't start at "
264 "base queue. q: %d, eq: %d\n",
265 (int)queue, static_priority_end);
266 return CVMX_PKO_INVALID_PRIORITY;
267 }
268 }
269 if (static_priority_base > 0) {
270 cvmx_dprintf("ERROR: cvmx_pko_config_port: Static "
271 "priority queues don't start at base "
272 "queue. sq: %d\n",
273 static_priority_base);
274 return CVMX_PKO_INVALID_PRIORITY;
275 }
276#if 0
277 cvmx_dprintf("Port %d: Static priority queue base: %d, "
278 "end: %d\n", port,
279 static_priority_base, static_priority_end);
280#endif
281 }
282 /*
283 * At this point, static_priority_base and static_priority_end
284 * are either both -1, or are valid start/end queue
285 * numbers.
286 */
287
288 result_code = CVMX_PKO_SUCCESS;
289
290#ifdef PKO_DEBUG
291 cvmx_dprintf("num queues: %d (%lld,%lld)\n", num_queues,
292 CVMX_PKO_QUEUES_PER_PORT_INTERFACE0,
293 CVMX_PKO_QUEUES_PER_PORT_INTERFACE1);
294#endif
295
296 for (queue = 0; queue < num_queues; queue++) {
297 uint64_t *buf_ptr = NULL;
298
299 config1.u64 = 0;
300 config1.s.idx3 = queue >> 3;
301 config1.s.qid7 = (base_queue + queue) >> 7;
302
303 config.u64 = 0;
304 config.s.tail = queue == (num_queues - 1);
305 config.s.index = queue;
306 config.s.port = port;
307 config.s.queue = base_queue + queue;
308
309 if (!cvmx_octeon_is_pass1()) {
310 config.s.static_p = static_priority_base >= 0;
311 config.s.static_q = (int)queue <= static_priority_end;
312 config.s.s_tail = (int)queue == static_priority_end;
313 }
314 /*
315 * Convert the priority into an enable bit field. Try
316 * to space the bits out evenly so the packet don't
317 * get grouped up
318 */
319 switch ((int)priority[queue]) {
320 case 0:
321 config.s.qos_mask = 0x00;
322 break;
323 case 1:
324 config.s.qos_mask = 0x01;
325 break;
326 case 2:
327 config.s.qos_mask = 0x11;
328 break;
329 case 3:
330 config.s.qos_mask = 0x49;
331 break;
332 case 4:
333 config.s.qos_mask = 0x55;
334 break;
335 case 5:
336 config.s.qos_mask = 0x57;
337 break;
338 case 6:
339 config.s.qos_mask = 0x77;
340 break;
341 case 7:
342 config.s.qos_mask = 0x7f;
343 break;
344 case 8:
345 config.s.qos_mask = 0xff;
346 break;
347 case CVMX_PKO_QUEUE_STATIC_PRIORITY:
348 /* Pass 1 will fall through to the error case */
349 if (!cvmx_octeon_is_pass1()) {
350 config.s.qos_mask = 0xff;
351 break;
352 }
353 default:
354 cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid "
355 "priority %llu\n",
356 (unsigned long long)priority[queue]);
357 config.s.qos_mask = 0xff;
358 result_code = CVMX_PKO_INVALID_PRIORITY;
359 break;
360 }
361
362 if (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID) {
363 cvmx_cmd_queue_result_t cmd_res =
364 cvmx_cmd_queue_initialize(CVMX_CMD_QUEUE_PKO
365 (base_queue + queue),
366 CVMX_PKO_MAX_QUEUE_DEPTH,
367 CVMX_FPA_OUTPUT_BUFFER_POOL,
368 CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE
369 -
370 CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST
371 * 8);
372 if (cmd_res != CVMX_CMD_QUEUE_SUCCESS) {
373 switch (cmd_res) {
374 case CVMX_CMD_QUEUE_NO_MEMORY:
375 cvmx_dprintf("ERROR: "
376 "cvmx_pko_config_port: "
377 "Unable to allocate "
378 "output buffer.\n");
379 return CVMX_PKO_NO_MEMORY;
380 case CVMX_CMD_QUEUE_ALREADY_SETUP:
381 cvmx_dprintf
382 ("ERROR: cvmx_pko_config_port: Port already setup.\n");
383 return CVMX_PKO_PORT_ALREADY_SETUP;
384 case CVMX_CMD_QUEUE_INVALID_PARAM:
385 default:
386 cvmx_dprintf
387 ("ERROR: cvmx_pko_config_port: Command queue initialization failed.\n");
388 return CVMX_PKO_CMD_QUEUE_INIT_ERROR;
389 }
390 }
391
392 buf_ptr =
393 (uint64_t *)
394 cvmx_cmd_queue_buffer(CVMX_CMD_QUEUE_PKO
395 (base_queue + queue));
396 config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr);
397 } else
398 config.s.buf_ptr = 0;
399
400 CVMX_SYNCWS;
401
402 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX))
403 cvmx_write_csr(CVMX_PKO_REG_QUEUE_PTRS1, config1.u64);
404 cvmx_write_csr(CVMX_PKO_MEM_QUEUE_PTRS, config.u64);
405 }
406
407 return result_code;
408}
409
410#ifdef PKO_DEBUG
411/**
412 * Show map of ports -> queues for different cores.
413 */
414void cvmx_pko_show_queue_map()
415{
416 int core, port;
417 int pko_output_ports = 36;
418
419 cvmx_dprintf("port");
420 for (port = 0; port < pko_output_ports; port++)
421 cvmx_dprintf("%3d ", port);
422 cvmx_dprintf("\n");
423
424 for (core = 0; core < CVMX_MAX_CORES; core++) {
425 cvmx_dprintf("\n%2d: ", core);
426 for (port = 0; port < pko_output_ports; port++) {
427 cvmx_dprintf("%3d ",
428 cvmx_pko_get_base_queue_per_core(port,
429 core));
430 }
431 }
432 cvmx_dprintf("\n");
433}
434#endif
435
436/**
437 * Rate limit a PKO port to a max packets/sec. This function is only
438 * supported on CN51XX and higher, excluding CN58XX.
439 *
440 * @port: Port to rate limit
441 * @packets_s: Maximum packet/sec
442 * @burst: Maximum number of packets to burst in a row before rate
443 * limiting cuts in.
444 *
445 * Returns Zero on success, negative on failure
446 */
447int cvmx_pko_rate_limit_packets(int port, int packets_s, int burst)
448{
449 union cvmx_pko_mem_port_rate0 pko_mem_port_rate0;
450 union cvmx_pko_mem_port_rate1 pko_mem_port_rate1;
451
452 pko_mem_port_rate0.u64 = 0;
453 pko_mem_port_rate0.s.pid = port;
454 pko_mem_port_rate0.s.rate_pkt =
455 cvmx_sysinfo_get()->cpu_clock_hz / packets_s / 16;
456 /* No cost per word since we are limited by packets/sec, not bits/sec */
457 pko_mem_port_rate0.s.rate_word = 0;
458
459 pko_mem_port_rate1.u64 = 0;
460 pko_mem_port_rate1.s.pid = port;
461 pko_mem_port_rate1.s.rate_lim =
462 ((uint64_t) pko_mem_port_rate0.s.rate_pkt * burst) >> 8;
463
464 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
465 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
466 return 0;
467}
468
469/**
470 * Rate limit a PKO port to a max bits/sec. This function is only
471 * supported on CN51XX and higher, excluding CN58XX.
472 *
473 * @port: Port to rate limit
474 * @bits_s: PKO rate limit in bits/sec
475 * @burst: Maximum number of bits to burst before rate
476 * limiting cuts in.
477 *
478 * Returns Zero on success, negative on failure
479 */
480int cvmx_pko_rate_limit_bits(int port, uint64_t bits_s, int burst)
481{
482 union cvmx_pko_mem_port_rate0 pko_mem_port_rate0;
483 union cvmx_pko_mem_port_rate1 pko_mem_port_rate1;
484 uint64_t clock_rate = cvmx_sysinfo_get()->cpu_clock_hz;
485 uint64_t tokens_per_bit = clock_rate * 16 / bits_s;
486
487 pko_mem_port_rate0.u64 = 0;
488 pko_mem_port_rate0.s.pid = port;
489 /*
490 * Each packet has a 12 bytes of interframe gap, an 8 byte
491 * preamble, and a 4 byte CRC. These are not included in the
492 * per word count. Multiply by 8 to covert to bits and divide
493 * by 256 for limit granularity.
494 */
495 pko_mem_port_rate0.s.rate_pkt = (12 + 8 + 4) * 8 * tokens_per_bit / 256;
496 /* Each 8 byte word has 64bits */
497 pko_mem_port_rate0.s.rate_word = 64 * tokens_per_bit;
498
499 pko_mem_port_rate1.u64 = 0;
500 pko_mem_port_rate1.s.pid = port;
501 pko_mem_port_rate1.s.rate_lim = tokens_per_bit * burst / 256;
502
503 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE0, pko_mem_port_rate0.u64);
504 cvmx_write_csr(CVMX_PKO_MEM_PORT_RATE1, pko_mem_port_rate1.u64);
505 return 0;
506}
diff --git a/arch/mips/cavium-octeon/executive/cvmx-spi.c b/arch/mips/cavium-octeon/executive/cvmx-spi.c
new file mode 100644
index 000000000000..74afb1710cd9
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-spi.c
@@ -0,0 +1,667 @@
1/***********************license start***************
2 * Author: Cavium Networks
3 *
4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK
6 *
7 * Copyright (c) 2003-2008 Cavium Networks
8 *
9 * This file is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License, Version 2, as
11 * published by the Free Software Foundation.
12 *
13 * This file is distributed in the hope that it will be useful, but
14 * AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty
15 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
16 * NONINFRINGEMENT. See the GNU General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this file; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 * or visit http://www.gnu.org/licenses/.
23 *
24 * This file may also be available under a different license from Cavium.
25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/
27
28/*
29 *
30 * Support library for the SPI
31 */
32#include <asm/octeon/octeon.h>
33
34#include <asm/octeon/cvmx-config.h>
35
36#include <asm/octeon/cvmx-pko.h>
37#include <asm/octeon/cvmx-spi.h>
38
39#include <asm/octeon/cvmx-spxx-defs.h>
40#include <asm/octeon/cvmx-stxx-defs.h>
41#include <asm/octeon/cvmx-srxx-defs.h>
42
43#define INVOKE_CB(function_p, args...) \
44 do { \
45 if (function_p) { \
46 res = function_p(args); \
47 if (res) \
48 return res; \
49 } \
50 } while (0)
51
52#if CVMX_ENABLE_DEBUG_PRINTS
53static const char *modes[] =
54 { "UNKNOWN", "TX Halfplex", "Rx Halfplex", "Duplex" };
55#endif
56
57/* Default callbacks, can be overridden
58 * using cvmx_spi_get_callbacks/cvmx_spi_set_callbacks
59 */
60static cvmx_spi_callbacks_t cvmx_spi_callbacks = {
61 .reset_cb = cvmx_spi_reset_cb,
62 .calendar_setup_cb = cvmx_spi_calendar_setup_cb,
63 .clock_detect_cb = cvmx_spi_clock_detect_cb,
64 .training_cb = cvmx_spi_training_cb,
65 .calendar_sync_cb = cvmx_spi_calendar_sync_cb,
66 .interface_up_cb = cvmx_spi_interface_up_cb
67};
68
69/**
70 * Get current SPI4 initialization callbacks
71 *
72 * @callbacks: Pointer to the callbacks structure.to fill
73 *
74 * Returns Pointer to cvmx_spi_callbacks_t structure.
75 */
76void cvmx_spi_get_callbacks(cvmx_spi_callbacks_t *callbacks)
77{
78 memcpy(callbacks, &cvmx_spi_callbacks, sizeof(cvmx_spi_callbacks));
79}
80
81/**
82 * Set new SPI4 initialization callbacks
83 *
84 * @new_callbacks: Pointer to an updated callbacks structure.
85 */
86void cvmx_spi_set_callbacks(cvmx_spi_callbacks_t *new_callbacks)
87{
88 memcpy(&cvmx_spi_callbacks, new_callbacks, sizeof(cvmx_spi_callbacks));
89}
90
91/**
92 * Initialize and start the SPI interface.
93 *
94 * @interface: The identifier of the packet interface to configure and
95 * use as a SPI interface.
96 * @mode: The operating mode for the SPI interface. The interface
97 * can operate as a full duplex (both Tx and Rx data paths
98 * active) or as a halfplex (either the Tx data path is
99 * active or the Rx data path is active, but not both).
100 * @timeout: Timeout to wait for clock synchronization in seconds
101 * @num_ports: Number of SPI ports to configure
102 *
103 * Returns Zero on success, negative of failure.
104 */
105int cvmx_spi_start_interface(int interface, cvmx_spi_mode_t mode, int timeout,
106 int num_ports)
107{
108 int res = -1;
109
110 if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
111 return res;
112
113 /* Callback to perform SPI4 reset */
114 INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode);
115
116 /* Callback to perform calendar setup */
117 INVOKE_CB(cvmx_spi_callbacks.calendar_setup_cb, interface, mode,
118 num_ports);
119
120 /* Callback to perform clock detection */
121 INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
122
123 /* Callback to perform SPI4 link training */
124 INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
125
126 /* Callback to perform calendar sync */
127 INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode,
128 timeout);
129
130 /* Callback to handle interface coming up */
131 INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
132
133 return res;
134}
135
136/**
137 * This routine restarts the SPI interface after it has lost synchronization
138 * with its correspondent system.
139 *
140 * @interface: The identifier of the packet interface to configure and
141 * use as a SPI interface.
142 * @mode: The operating mode for the SPI interface. The interface
143 * can operate as a full duplex (both Tx and Rx data paths
144 * active) or as a halfplex (either the Tx data path is
145 * active or the Rx data path is active, but not both).
146 * @timeout: Timeout to wait for clock synchronization in seconds
147 *
148 * Returns Zero on success, negative of failure.
149 */
150int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout)
151{
152 int res = -1;
153
154 if (!(OCTEON_IS_MODEL(OCTEON_CN38XX) || OCTEON_IS_MODEL(OCTEON_CN58XX)))
155 return res;
156
157 cvmx_dprintf("SPI%d: Restart %s\n", interface, modes[mode]);
158
159 /* Callback to perform SPI4 reset */
160 INVOKE_CB(cvmx_spi_callbacks.reset_cb, interface, mode);
161
162 /* NOTE: Calendar setup is not performed during restart */
163 /* Refer to cvmx_spi_start_interface() for the full sequence */
164
165 /* Callback to perform clock detection */
166 INVOKE_CB(cvmx_spi_callbacks.clock_detect_cb, interface, mode, timeout);
167
168 /* Callback to perform SPI4 link training */
169 INVOKE_CB(cvmx_spi_callbacks.training_cb, interface, mode, timeout);
170
171 /* Callback to perform calendar sync */
172 INVOKE_CB(cvmx_spi_callbacks.calendar_sync_cb, interface, mode,
173 timeout);
174
175 /* Callback to handle interface coming up */
176 INVOKE_CB(cvmx_spi_callbacks.interface_up_cb, interface, mode);
177
178 return res;
179}
180
181/**
182 * Callback to perform SPI4 reset
183 *
184 * @interface: The identifier of the packet interface to configure and
185 * use as a SPI interface.
186 * @mode: The operating mode for the SPI interface. The interface
187 * can operate as a full duplex (both Tx and Rx data paths
188 * active) or as a halfplex (either the Tx data path is
189 * active or the Rx data path is active, but not both).
190 *
191 * Returns Zero on success, non-zero error code on failure (will cause
192 * SPI initialization to abort)
193 */
194int cvmx_spi_reset_cb(int interface, cvmx_spi_mode_t mode)
195{
196 union cvmx_spxx_dbg_deskew_ctl spxx_dbg_deskew_ctl;
197 union cvmx_spxx_clk_ctl spxx_clk_ctl;
198 union cvmx_spxx_bist_stat spxx_bist_stat;
199 union cvmx_spxx_int_msk spxx_int_msk;
200 union cvmx_stxx_int_msk stxx_int_msk;
201 union cvmx_spxx_trn4_ctl spxx_trn4_ctl;
202 int index;
203 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
204
205 /* Disable SPI error events while we run BIST */
206 spxx_int_msk.u64 = cvmx_read_csr(CVMX_SPXX_INT_MSK(interface));
207 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), 0);
208 stxx_int_msk.u64 = cvmx_read_csr(CVMX_STXX_INT_MSK(interface));
209 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), 0);
210
211 /* Run BIST in the SPI interface */
212 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), 0);
213 cvmx_write_csr(CVMX_STXX_COM_CTL(interface), 0);
214 spxx_clk_ctl.u64 = 0;
215 spxx_clk_ctl.s.runbist = 1;
216 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
217 cvmx_wait(10 * MS);
218 spxx_bist_stat.u64 = cvmx_read_csr(CVMX_SPXX_BIST_STAT(interface));
219 if (spxx_bist_stat.s.stat0)
220 cvmx_dprintf
221 ("ERROR SPI%d: BIST failed on receive datapath FIFO\n",
222 interface);
223 if (spxx_bist_stat.s.stat1)
224 cvmx_dprintf("ERROR SPI%d: BIST failed on RX calendar table\n",
225 interface);
226 if (spxx_bist_stat.s.stat2)
227 cvmx_dprintf("ERROR SPI%d: BIST failed on TX calendar table\n",
228 interface);
229
230 /* Clear the calendar table after BIST to fix parity errors */
231 for (index = 0; index < 32; index++) {
232 union cvmx_srxx_spi4_calx srxx_spi4_calx;
233 union cvmx_stxx_spi4_calx stxx_spi4_calx;
234
235 srxx_spi4_calx.u64 = 0;
236 srxx_spi4_calx.s.oddpar = 1;
237 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface),
238 srxx_spi4_calx.u64);
239
240 stxx_spi4_calx.u64 = 0;
241 stxx_spi4_calx.s.oddpar = 1;
242 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface),
243 stxx_spi4_calx.u64);
244 }
245
246 /* Re enable reporting of error interrupts */
247 cvmx_write_csr(CVMX_SPXX_INT_REG(interface),
248 cvmx_read_csr(CVMX_SPXX_INT_REG(interface)));
249 cvmx_write_csr(CVMX_SPXX_INT_MSK(interface), spxx_int_msk.u64);
250 cvmx_write_csr(CVMX_STXX_INT_REG(interface),
251 cvmx_read_csr(CVMX_STXX_INT_REG(interface)));
252 cvmx_write_csr(CVMX_STXX_INT_MSK(interface), stxx_int_msk.u64);
253
254 /* Setup the CLKDLY right in the middle */
255 spxx_clk_ctl.u64 = 0;
256 spxx_clk_ctl.s.seetrn = 0;
257 spxx_clk_ctl.s.clkdly = 0x10;
258 spxx_clk_ctl.s.runbist = 0;
259 spxx_clk_ctl.s.statdrv = 0;
260 /* This should always be on the opposite edge as statdrv */
261 spxx_clk_ctl.s.statrcv = 1;
262 spxx_clk_ctl.s.sndtrn = 0;
263 spxx_clk_ctl.s.drptrn = 0;
264 spxx_clk_ctl.s.rcvtrn = 0;
265 spxx_clk_ctl.s.srxdlck = 0;
266 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
267 cvmx_wait(100 * MS);
268
269 /* Reset SRX0 DLL */
270 spxx_clk_ctl.s.srxdlck = 1;
271 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
272
273 /* Waiting for Inf0 Spi4 RX DLL to lock */
274 cvmx_wait(100 * MS);
275
276 /* Enable dynamic alignment */
277 spxx_trn4_ctl.s.trntest = 0;
278 spxx_trn4_ctl.s.jitter = 1;
279 spxx_trn4_ctl.s.clr_boot = 1;
280 spxx_trn4_ctl.s.set_boot = 0;
281 if (OCTEON_IS_MODEL(OCTEON_CN58XX))
282 spxx_trn4_ctl.s.maxdist = 3;
283 else
284 spxx_trn4_ctl.s.maxdist = 8;
285 spxx_trn4_ctl.s.macro_en = 1;
286 spxx_trn4_ctl.s.mux_en = 1;
287 cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
288
289 spxx_dbg_deskew_ctl.u64 = 0;
290 cvmx_write_csr(CVMX_SPXX_DBG_DESKEW_CTL(interface),
291 spxx_dbg_deskew_ctl.u64);
292
293 return 0;
294}
295
296/**
297 * Callback to setup calendar and miscellaneous settings before clock detection
298 *
299 * @interface: The identifier of the packet interface to configure and
300 * use as a SPI interface.
301 * @mode: The operating mode for the SPI interface. The interface
302 * can operate as a full duplex (both Tx and Rx data paths
303 * active) or as a halfplex (either the Tx data path is
304 * active or the Rx data path is active, but not both).
305 * @num_ports: Number of ports to configure on SPI
306 *
307 * Returns Zero on success, non-zero error code on failure (will cause
308 * SPI initialization to abort)
309 */
310int cvmx_spi_calendar_setup_cb(int interface, cvmx_spi_mode_t mode,
311 int num_ports)
312{
313 int port;
314 int index;
315 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
316 union cvmx_srxx_com_ctl srxx_com_ctl;
317 union cvmx_srxx_spi4_stat srxx_spi4_stat;
318
319 /* SRX0 number of Ports */
320 srxx_com_ctl.u64 = 0;
321 srxx_com_ctl.s.prts = num_ports - 1;
322 srxx_com_ctl.s.st_en = 0;
323 srxx_com_ctl.s.inf_en = 0;
324 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
325
326 /* SRX0 Calendar Table. This round robbins through all ports */
327 port = 0;
328 index = 0;
329 while (port < num_ports) {
330 union cvmx_srxx_spi4_calx srxx_spi4_calx;
331 srxx_spi4_calx.u64 = 0;
332 srxx_spi4_calx.s.prt0 = port++;
333 srxx_spi4_calx.s.prt1 = port++;
334 srxx_spi4_calx.s.prt2 = port++;
335 srxx_spi4_calx.s.prt3 = port++;
336 srxx_spi4_calx.s.oddpar =
337 ~(cvmx_dpop(srxx_spi4_calx.u64) & 1);
338 cvmx_write_csr(CVMX_SRXX_SPI4_CALX(index, interface),
339 srxx_spi4_calx.u64);
340 index++;
341 }
342 srxx_spi4_stat.u64 = 0;
343 srxx_spi4_stat.s.len = num_ports;
344 srxx_spi4_stat.s.m = 1;
345 cvmx_write_csr(CVMX_SRXX_SPI4_STAT(interface),
346 srxx_spi4_stat.u64);
347 }
348
349 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
350 union cvmx_stxx_arb_ctl stxx_arb_ctl;
351 union cvmx_gmxx_tx_spi_max gmxx_tx_spi_max;
352 union cvmx_gmxx_tx_spi_thresh gmxx_tx_spi_thresh;
353 union cvmx_gmxx_tx_spi_ctl gmxx_tx_spi_ctl;
354 union cvmx_stxx_spi4_stat stxx_spi4_stat;
355 union cvmx_stxx_spi4_dat stxx_spi4_dat;
356
357 /* STX0 Config */
358 stxx_arb_ctl.u64 = 0;
359 stxx_arb_ctl.s.igntpa = 0;
360 stxx_arb_ctl.s.mintrn = 0;
361 cvmx_write_csr(CVMX_STXX_ARB_CTL(interface), stxx_arb_ctl.u64);
362
363 gmxx_tx_spi_max.u64 = 0;
364 gmxx_tx_spi_max.s.max1 = 8;
365 gmxx_tx_spi_max.s.max2 = 4;
366 gmxx_tx_spi_max.s.slice = 0;
367 cvmx_write_csr(CVMX_GMXX_TX_SPI_MAX(interface),
368 gmxx_tx_spi_max.u64);
369
370 gmxx_tx_spi_thresh.u64 = 0;
371 gmxx_tx_spi_thresh.s.thresh = 4;
372 cvmx_write_csr(CVMX_GMXX_TX_SPI_THRESH(interface),
373 gmxx_tx_spi_thresh.u64);
374
375 gmxx_tx_spi_ctl.u64 = 0;
376 gmxx_tx_spi_ctl.s.tpa_clr = 0;
377 gmxx_tx_spi_ctl.s.cont_pkt = 0;
378 cvmx_write_csr(CVMX_GMXX_TX_SPI_CTL(interface),
379 gmxx_tx_spi_ctl.u64);
380
381 /* STX0 Training Control */
382 stxx_spi4_dat.u64 = 0;
383 /*Minimum needed by dynamic alignment */
384 stxx_spi4_dat.s.alpha = 32;
385 stxx_spi4_dat.s.max_t = 0xFFFF; /*Minimum interval is 0x20 */
386 cvmx_write_csr(CVMX_STXX_SPI4_DAT(interface),
387 stxx_spi4_dat.u64);
388
389 /* STX0 Calendar Table. This round robbins through all ports */
390 port = 0;
391 index = 0;
392 while (port < num_ports) {
393 union cvmx_stxx_spi4_calx stxx_spi4_calx;
394 stxx_spi4_calx.u64 = 0;
395 stxx_spi4_calx.s.prt0 = port++;
396 stxx_spi4_calx.s.prt1 = port++;
397 stxx_spi4_calx.s.prt2 = port++;
398 stxx_spi4_calx.s.prt3 = port++;
399 stxx_spi4_calx.s.oddpar =
400 ~(cvmx_dpop(stxx_spi4_calx.u64) & 1);
401 cvmx_write_csr(CVMX_STXX_SPI4_CALX(index, interface),
402 stxx_spi4_calx.u64);
403 index++;
404 }
405 stxx_spi4_stat.u64 = 0;
406 stxx_spi4_stat.s.len = num_ports;
407 stxx_spi4_stat.s.m = 1;
408 cvmx_write_csr(CVMX_STXX_SPI4_STAT(interface),
409 stxx_spi4_stat.u64);
410 }
411
412 return 0;
413}
414
415/**
416 * Callback to perform clock detection
417 *
418 * @interface: The identifier of the packet interface to configure and
419 * use as a SPI interface.
420 * @mode: The operating mode for the SPI interface. The interface
421 * can operate as a full duplex (both Tx and Rx data paths
422 * active) or as a halfplex (either the Tx data path is
423 * active or the Rx data path is active, but not both).
424 * @timeout: Timeout to wait for clock synchronization in seconds
425 *
426 * Returns Zero on success, non-zero error code on failure (will cause
427 * SPI initialization to abort)
428 */
429int cvmx_spi_clock_detect_cb(int interface, cvmx_spi_mode_t mode, int timeout)
430{
431 int clock_transitions;
432 union cvmx_spxx_clk_stat stat;
433 uint64_t timeout_time;
434 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
435
436 /*
437 * Regardless of operating mode, both Tx and Rx clocks must be
438 * present for the SPI interface to operate.
439 */
440 cvmx_dprintf("SPI%d: Waiting to see TsClk...\n", interface);
441 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
442 /*
443 * Require 100 clock transitions in order to avoid any noise
444 * in the beginning.
445 */
446 clock_transitions = 100;
447 do {
448 stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
449 if (stat.s.s4clk0 && stat.s.s4clk1 && clock_transitions) {
450 /*
451 * We've seen a clock transition, so decrement
452 * the number we still need.
453 */
454 clock_transitions--;
455 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
456 stat.s.s4clk0 = 0;
457 stat.s.s4clk1 = 0;
458 }
459 if (cvmx_get_cycle() > timeout_time) {
460 cvmx_dprintf("SPI%d: Timeout\n", interface);
461 return -1;
462 }
463 } while (stat.s.s4clk0 == 0 || stat.s.s4clk1 == 0);
464
465 cvmx_dprintf("SPI%d: Waiting to see RsClk...\n", interface);
466 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
467 /*
468 * Require 100 clock transitions in order to avoid any noise in the
469 * beginning.
470 */
471 clock_transitions = 100;
472 do {
473 stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
474 if (stat.s.d4clk0 && stat.s.d4clk1 && clock_transitions) {
475 /*
476 * We've seen a clock transition, so decrement
477 * the number we still need
478 */
479 clock_transitions--;
480 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
481 stat.s.d4clk0 = 0;
482 stat.s.d4clk1 = 0;
483 }
484 if (cvmx_get_cycle() > timeout_time) {
485 cvmx_dprintf("SPI%d: Timeout\n", interface);
486 return -1;
487 }
488 } while (stat.s.d4clk0 == 0 || stat.s.d4clk1 == 0);
489
490 return 0;
491}
492
493/**
494 * Callback to perform link training
495 *
496 * @interface: The identifier of the packet interface to configure and
497 * use as a SPI interface.
498 * @mode: The operating mode for the SPI interface. The interface
499 * can operate as a full duplex (both Tx and Rx data paths
500 * active) or as a halfplex (either the Tx data path is
501 * active or the Rx data path is active, but not both).
502 * @timeout: Timeout to wait for link to be trained (in seconds)
503 *
504 * Returns Zero on success, non-zero error code on failure (will cause
505 * SPI initialization to abort)
506 */
507int cvmx_spi_training_cb(int interface, cvmx_spi_mode_t mode, int timeout)
508{
509 union cvmx_spxx_trn4_ctl spxx_trn4_ctl;
510 union cvmx_spxx_clk_stat stat;
511 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
512 uint64_t timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
513 int rx_training_needed;
514
515 /* SRX0 & STX0 Inf0 Links are configured - begin training */
516 union cvmx_spxx_clk_ctl spxx_clk_ctl;
517 spxx_clk_ctl.u64 = 0;
518 spxx_clk_ctl.s.seetrn = 0;
519 spxx_clk_ctl.s.clkdly = 0x10;
520 spxx_clk_ctl.s.runbist = 0;
521 spxx_clk_ctl.s.statdrv = 0;
522 /* This should always be on the opposite edge as statdrv */
523 spxx_clk_ctl.s.statrcv = 1;
524 spxx_clk_ctl.s.sndtrn = 1;
525 spxx_clk_ctl.s.drptrn = 1;
526 spxx_clk_ctl.s.rcvtrn = 1;
527 spxx_clk_ctl.s.srxdlck = 1;
528 cvmx_write_csr(CVMX_SPXX_CLK_CTL(interface), spxx_clk_ctl.u64);
529 cvmx_wait(1000 * MS);
530
531 /* SRX0 clear the boot bit */
532 spxx_trn4_ctl.u64 = cvmx_read_csr(CVMX_SPXX_TRN4_CTL(interface));
533 spxx_trn4_ctl.s.clr_boot = 1;
534 cvmx_write_csr(CVMX_SPXX_TRN4_CTL(interface), spxx_trn4_ctl.u64);
535
536 /* Wait for the training sequence to complete */
537 cvmx_dprintf("SPI%d: Waiting for training\n", interface);
538 cvmx_wait(1000 * MS);
539 /* Wait a really long time here */
540 timeout_time = cvmx_get_cycle() + 1000ull * MS * 600;
541 /*
542 * The HRM says we must wait for 34 + 16 * MAXDIST training sequences.
543 * We'll be pessimistic and wait for a lot more.
544 */
545 rx_training_needed = 500;
546 do {
547 stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
548 if (stat.s.srxtrn && rx_training_needed) {
549 rx_training_needed--;
550 cvmx_write_csr(CVMX_SPXX_CLK_STAT(interface), stat.u64);
551 stat.s.srxtrn = 0;
552 }
553 if (cvmx_get_cycle() > timeout_time) {
554 cvmx_dprintf("SPI%d: Timeout\n", interface);
555 return -1;
556 }
557 } while (stat.s.srxtrn == 0);
558
559 return 0;
560}
561
562/**
563 * Callback to perform calendar data synchronization
564 *
565 * @interface: The identifier of the packet interface to configure and
566 * use as a SPI interface.
567 * @mode: The operating mode for the SPI interface. The interface
568 * can operate as a full duplex (both Tx and Rx data paths
569 * active) or as a halfplex (either the Tx data path is
570 * active or the Rx data path is active, but not both).
571 * @timeout: Timeout to wait for calendar data in seconds
572 *
573 * Returns Zero on success, non-zero error code on failure (will cause
574 * SPI initialization to abort)
575 */
576int cvmx_spi_calendar_sync_cb(int interface, cvmx_spi_mode_t mode, int timeout)
577{
578 uint64_t MS = cvmx_sysinfo_get()->cpu_clock_hz / 1000;
579 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
580 /* SRX0 interface should be good, send calendar data */
581 union cvmx_srxx_com_ctl srxx_com_ctl;
582 cvmx_dprintf
583 ("SPI%d: Rx is synchronized, start sending calendar data\n",
584 interface);
585 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
586 srxx_com_ctl.s.inf_en = 1;
587 srxx_com_ctl.s.st_en = 1;
588 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
589 }
590
591 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
592 /* STX0 has achieved sync */
593 /* The corespondant board should be sending calendar data */
594 /* Enable the STX0 STAT receiver. */
595 union cvmx_spxx_clk_stat stat;
596 uint64_t timeout_time;
597 union cvmx_stxx_com_ctl stxx_com_ctl;
598 stxx_com_ctl.u64 = 0;
599 stxx_com_ctl.s.st_en = 1;
600 cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
601
602 /* Waiting for calendar sync on STX0 STAT */
603 cvmx_dprintf("SPI%d: Waiting to sync on STX[%d] STAT\n",
604 interface, interface);
605 timeout_time = cvmx_get_cycle() + 1000ull * MS * timeout;
606 /* SPX0_CLK_STAT - SPX0_CLK_STAT[STXCAL] should be 1 (bit10) */
607 do {
608 stat.u64 = cvmx_read_csr(CVMX_SPXX_CLK_STAT(interface));
609 if (cvmx_get_cycle() > timeout_time) {
610 cvmx_dprintf("SPI%d: Timeout\n", interface);
611 return -1;
612 }
613 } while (stat.s.stxcal == 0);
614 }
615
616 return 0;
617}
618
619/**
620 * Callback to handle interface up
621 *
622 * @interface: The identifier of the packet interface to configure and
623 * use as a SPI interface.
624 * @mode: The operating mode for the SPI interface. The interface
625 * can operate as a full duplex (both Tx and Rx data paths
626 * active) or as a halfplex (either the Tx data path is
627 * active or the Rx data path is active, but not both).
628 *
629 * Returns Zero on success, non-zero error code on failure (will cause
630 * SPI initialization to abort)
631 */
632int cvmx_spi_interface_up_cb(int interface, cvmx_spi_mode_t mode)
633{
634 union cvmx_gmxx_rxx_frm_min gmxx_rxx_frm_min;
635 union cvmx_gmxx_rxx_frm_max gmxx_rxx_frm_max;
636 union cvmx_gmxx_rxx_jabber gmxx_rxx_jabber;
637
638 if (mode & CVMX_SPI_MODE_RX_HALFPLEX) {
639 union cvmx_srxx_com_ctl srxx_com_ctl;
640 srxx_com_ctl.u64 = cvmx_read_csr(CVMX_SRXX_COM_CTL(interface));
641 srxx_com_ctl.s.inf_en = 1;
642 cvmx_write_csr(CVMX_SRXX_COM_CTL(interface), srxx_com_ctl.u64);
643 cvmx_dprintf("SPI%d: Rx is now up\n", interface);
644 }
645
646 if (mode & CVMX_SPI_MODE_TX_HALFPLEX) {
647 union cvmx_stxx_com_ctl stxx_com_ctl;
648 stxx_com_ctl.u64 = cvmx_read_csr(CVMX_STXX_COM_CTL(interface));
649 stxx_com_ctl.s.inf_en = 1;
650 cvmx_write_csr(CVMX_STXX_COM_CTL(interface), stxx_com_ctl.u64);
651 cvmx_dprintf("SPI%d: Tx is now up\n", interface);
652 }
653
654 gmxx_rxx_frm_min.u64 = 0;
655 gmxx_rxx_frm_min.s.len = 64;
656 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MIN(0, interface),
657 gmxx_rxx_frm_min.u64);
658 gmxx_rxx_frm_max.u64 = 0;
659 gmxx_rxx_frm_max.s.len = 64 * 1024 - 4;
660 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX(0, interface),
661 gmxx_rxx_frm_max.u64);
662 gmxx_rxx_jabber.u64 = 0;
663 gmxx_rxx_jabber.s.cnt = 64 * 1024 - 4;
664 cvmx_write_csr(CVMX_GMXX_RXX_JABBER(0, interface), gmxx_rxx_jabber.u64);
665
666 return 0;
667}