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.c711
-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.c554
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-spi.c205
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-util.c433
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c354
-rw-r--r--arch/mips/cavium-octeon/executive/cvmx-helper.c1116
-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
-rw-r--r--arch/mips/cavium-octeon/executive/octeon-model.c119
18 files changed, 6604 insertions, 35 deletions
diff --git a/arch/mips/cavium-octeon/executive/Makefile b/arch/mips/cavium-octeon/executive/Makefile
index 7f41c5be219..b6d6e841a98 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 00000000000..132bccc66a9
--- /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 00000000000..ad44b8bd805
--- /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 00000000000..fd2015331a2
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c
@@ -0,0 +1,711 @@
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 /* Board has 2 management ports */
121 if ((ipd_port >= CVMX_HELPER_BOARD_MGMT_IPD_PORT) &&
122 (ipd_port < (CVMX_HELPER_BOARD_MGMT_IPD_PORT + 2)))
123 return ipd_port - CVMX_HELPER_BOARD_MGMT_IPD_PORT;
124 /*
125 * Board has 4 SGMII ports. The PHYs start right after the MII
126 * ports MII0 = 0, MII1 = 1, SGMII = 2-5.
127 */
128 if ((ipd_port >= 0) && (ipd_port < 4))
129 return ipd_port + 2;
130 else
131 return -1;
132 case CVMX_BOARD_TYPE_EBH5600:
133 case CVMX_BOARD_TYPE_EBH5601:
134 case CVMX_BOARD_TYPE_EBH5610:
135 /* Board has 1 management port */
136 if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT)
137 return 0;
138 /*
139 * Board has 8 SGMII ports. 4 connect out, two connect
140 * to a switch, and 2 loop to each other
141 */
142 if ((ipd_port >= 0) && (ipd_port < 4))
143 return ipd_port + 1;
144 else
145 return -1;
146 case CVMX_BOARD_TYPE_CUST_NB5:
147 if (ipd_port == 2)
148 return 4;
149 else
150 return -1;
151 case CVMX_BOARD_TYPE_NIC_XLE_4G:
152 /* Board has 4 SGMII ports. connected QLM3(interface 1) */
153 if ((ipd_port >= 16) && (ipd_port < 20))
154 return ipd_port - 16 + 1;
155 else
156 return -1;
157 case CVMX_BOARD_TYPE_NIC_XLE_10G:
158 case CVMX_BOARD_TYPE_NIC10E:
159 return -1;
160 case CVMX_BOARD_TYPE_NIC4E:
161 if (ipd_port >= 0 && ipd_port <= 3)
162 return (ipd_port + 0x1f) & 0x1f;
163 else
164 return -1;
165 case CVMX_BOARD_TYPE_NIC2E:
166 if (ipd_port >= 0 && ipd_port <= 1)
167 return ipd_port + 1;
168 else
169 return -1;
170 case CVMX_BOARD_TYPE_BBGW_REF:
171 /*
172 * No PHYs are connected to Octeon, everything is
173 * through switch.
174 */
175 return -1;
176
177 case CVMX_BOARD_TYPE_CUST_WSX16:
178 if (ipd_port >= 0 && ipd_port <= 3)
179 return ipd_port;
180 else if (ipd_port >= 16 && ipd_port <= 19)
181 return ipd_port - 16 + 4;
182 else
183 return -1;
184 }
185
186 /* Some unknown board. Somebody forgot to update this function... */
187 cvmx_dprintf
188 ("cvmx_helper_board_get_mii_address: Unknown board type %d\n",
189 cvmx_sysinfo_get()->board_type);
190 return -1;
191}
192
193/**
194 * This function is the board specific method of determining an
195 * ethernet ports link speed. Most Octeon boards have Marvell PHYs
196 * and are handled by the fall through case. This function must be
197 * updated for boards that don't have the normal Marvell PHYs.
198 *
199 * This function must be modified for every new Octeon board.
200 * Internally it uses switch statements based on the cvmx_sysinfo
201 * data to determine board types and revisions. It relies on the
202 * fact that every Octeon board receives a unique board type
203 * enumeration from the bootloader.
204 *
205 * @ipd_port: IPD input port associated with the port we want to get link
206 * status for.
207 *
208 * Returns The ports link status. If the link isn't fully resolved, this must
209 * return zero.
210 */
211cvmx_helper_link_info_t __cvmx_helper_board_link_get(int ipd_port)
212{
213 cvmx_helper_link_info_t result;
214 int phy_addr;
215 int is_broadcom_phy = 0;
216
217 /* Give the user a chance to override the processing of this function */
218 if (cvmx_override_board_link_get)
219 return cvmx_override_board_link_get(ipd_port);
220
221 /* Unless we fix it later, all links are defaulted to down */
222 result.u64 = 0;
223
224 /*
225 * This switch statement should handle all ports that either don't use
226 * Marvell PHYS, or don't support in-band status.
227 */
228 switch (cvmx_sysinfo_get()->board_type) {
229 case CVMX_BOARD_TYPE_SIM:
230 /* The simulator gives you a simulated 1Gbps full duplex link */
231 result.s.link_up = 1;
232 result.s.full_duplex = 1;
233 result.s.speed = 1000;
234 return result;
235 case CVMX_BOARD_TYPE_EBH3100:
236 case CVMX_BOARD_TYPE_CN3010_EVB_HS5:
237 case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
238 case CVMX_BOARD_TYPE_CN3020_EVB_HS5:
239 /* Port 1 on these boards is always Gigabit */
240 if (ipd_port == 1) {
241 result.s.link_up = 1;
242 result.s.full_duplex = 1;
243 result.s.speed = 1000;
244 return result;
245 }
246 /* Fall through to the generic code below */
247 break;
248 case CVMX_BOARD_TYPE_CUST_NB5:
249 /* Port 1 on these boards is always Gigabit */
250 if (ipd_port == 1) {
251 result.s.link_up = 1;
252 result.s.full_duplex = 1;
253 result.s.speed = 1000;
254 return result;
255 } else /* The other port uses a broadcom PHY */
256 is_broadcom_phy = 1;
257 break;
258 case CVMX_BOARD_TYPE_BBGW_REF:
259 /* Port 1 on these boards is always Gigabit */
260 if (ipd_port == 2) {
261 /* Port 2 is not hooked up */
262 result.u64 = 0;
263 return result;
264 } else {
265 /* Ports 0 and 1 connect to the switch */
266 result.s.link_up = 1;
267 result.s.full_duplex = 1;
268 result.s.speed = 1000;
269 return result;
270 }
271 break;
272 }
273
274 phy_addr = cvmx_helper_board_get_mii_address(ipd_port);
275 if (phy_addr != -1) {
276 if (is_broadcom_phy) {
277 /*
278 * Below we are going to read SMI/MDIO
279 * register 0x19 which works on Broadcom
280 * parts
281 */
282 int phy_status =
283 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
284 0x19);
285 switch ((phy_status >> 8) & 0x7) {
286 case 0:
287 result.u64 = 0;
288 break;
289 case 1:
290 result.s.link_up = 1;
291 result.s.full_duplex = 0;
292 result.s.speed = 10;
293 break;
294 case 2:
295 result.s.link_up = 1;
296 result.s.full_duplex = 1;
297 result.s.speed = 10;
298 break;
299 case 3:
300 result.s.link_up = 1;
301 result.s.full_duplex = 0;
302 result.s.speed = 100;
303 break;
304 case 4:
305 result.s.link_up = 1;
306 result.s.full_duplex = 1;
307 result.s.speed = 100;
308 break;
309 case 5:
310 result.s.link_up = 1;
311 result.s.full_duplex = 1;
312 result.s.speed = 100;
313 break;
314 case 6:
315 result.s.link_up = 1;
316 result.s.full_duplex = 0;
317 result.s.speed = 1000;
318 break;
319 case 7:
320 result.s.link_up = 1;
321 result.s.full_duplex = 1;
322 result.s.speed = 1000;
323 break;
324 }
325 } else {
326 /*
327 * This code assumes we are using a Marvell
328 * Gigabit PHY. All the speed information can
329 * be read from register 17 in one
330 * go. Somebody using a different PHY will
331 * need to handle it above in the board
332 * specific area.
333 */
334 int phy_status =
335 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff, 17);
336
337 /*
338 * If the resolve bit 11 isn't set, see if
339 * autoneg is turned off (bit 12, reg 0). The
340 * resolve bit doesn't get set properly when
341 * autoneg is off, so force it.
342 */
343 if ((phy_status & (1 << 11)) == 0) {
344 int auto_status =
345 cvmx_mdio_read(phy_addr >> 8,
346 phy_addr & 0xff, 0);
347 if ((auto_status & (1 << 12)) == 0)
348 phy_status |= 1 << 11;
349 }
350
351 /*
352 * Only return a link if the PHY has finished
353 * auto negotiation and set the resolved bit
354 * (bit 11)
355 */
356 if (phy_status & (1 << 11)) {
357 result.s.link_up = 1;
358 result.s.full_duplex = ((phy_status >> 13) & 1);
359 switch ((phy_status >> 14) & 3) {
360 case 0: /* 10 Mbps */
361 result.s.speed = 10;
362 break;
363 case 1: /* 100 Mbps */
364 result.s.speed = 100;
365 break;
366 case 2: /* 1 Gbps */
367 result.s.speed = 1000;
368 break;
369 case 3: /* Illegal */
370 result.u64 = 0;
371 break;
372 }
373 }
374 }
375 } else if (OCTEON_IS_MODEL(OCTEON_CN3XXX)
376 || OCTEON_IS_MODEL(OCTEON_CN58XX)
377 || OCTEON_IS_MODEL(OCTEON_CN50XX)) {
378 /*
379 * We don't have a PHY address, so attempt to use
380 * in-band status. It is really important that boards
381 * not supporting in-band status never get
382 * here. Reading broken in-band status tends to do bad
383 * things
384 */
385 union cvmx_gmxx_rxx_rx_inbnd inband_status;
386 int interface = cvmx_helper_get_interface_num(ipd_port);
387 int index = cvmx_helper_get_interface_index_num(ipd_port);
388 inband_status.u64 =
389 cvmx_read_csr(CVMX_GMXX_RXX_RX_INBND(index, interface));
390
391 result.s.link_up = inband_status.s.status;
392 result.s.full_duplex = inband_status.s.duplex;
393 switch (inband_status.s.speed) {
394 case 0: /* 10 Mbps */
395 result.s.speed = 10;
396 break;
397 case 1: /* 100 Mbps */
398 result.s.speed = 100;
399 break;
400 case 2: /* 1 Gbps */
401 result.s.speed = 1000;
402 break;
403 case 3: /* Illegal */
404 result.u64 = 0;
405 break;
406 }
407 } else {
408 /*
409 * We don't have a PHY address and we don't have
410 * in-band status. There is no way to determine the
411 * link speed. Return down assuming this port isn't
412 * wired
413 */
414 result.u64 = 0;
415 }
416
417 /* If link is down, return all fields as zero. */
418 if (!result.s.link_up)
419 result.u64 = 0;
420
421 return result;
422}
423
424/**
425 * This function as a board specific method of changing the PHY
426 * speed, duplex, and auto-negotiation. This programs the PHY and
427 * not Octeon. This can be used to force Octeon's links to
428 * specific settings.
429 *
430 * @phy_addr: The address of the PHY to program
431 * @enable_autoneg:
432 * Non zero if you want to enable auto-negotiation.
433 * @link_info: Link speed to program. If the speed is zero and auto-negotiation
434 * is enabled, all possible negotiation speeds are advertised.
435 *
436 * Returns Zero on success, negative on failure
437 */
438int cvmx_helper_board_link_set_phy(int phy_addr,
439 cvmx_helper_board_set_phy_link_flags_types_t
440 link_flags,
441 cvmx_helper_link_info_t link_info)
442{
443
444 /* Set the flow control settings based on link_flags */
445 if ((link_flags & set_phy_link_flags_flow_control_mask) !=
446 set_phy_link_flags_flow_control_dont_touch) {
447 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
448 reg_autoneg_adver.u16 =
449 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
450 CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
451 reg_autoneg_adver.s.asymmetric_pause =
452 (link_flags & set_phy_link_flags_flow_control_mask) ==
453 set_phy_link_flags_flow_control_enable;
454 reg_autoneg_adver.s.pause =
455 (link_flags & set_phy_link_flags_flow_control_mask) ==
456 set_phy_link_flags_flow_control_enable;
457 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
458 CVMX_MDIO_PHY_REG_AUTONEG_ADVER,
459 reg_autoneg_adver.u16);
460 }
461
462 /* If speed isn't set and autoneg is on advertise all supported modes */
463 if ((link_flags & set_phy_link_flags_autoneg)
464 && (link_info.s.speed == 0)) {
465 cvmx_mdio_phy_reg_control_t reg_control;
466 cvmx_mdio_phy_reg_status_t reg_status;
467 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
468 cvmx_mdio_phy_reg_extended_status_t reg_extended_status;
469 cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
470
471 reg_status.u16 =
472 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
473 CVMX_MDIO_PHY_REG_STATUS);
474 reg_autoneg_adver.u16 =
475 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
476 CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
477 reg_autoneg_adver.s.advert_100base_t4 =
478 reg_status.s.capable_100base_t4;
479 reg_autoneg_adver.s.advert_10base_tx_full =
480 reg_status.s.capable_10_full;
481 reg_autoneg_adver.s.advert_10base_tx_half =
482 reg_status.s.capable_10_half;
483 reg_autoneg_adver.s.advert_100base_tx_full =
484 reg_status.s.capable_100base_x_full;
485 reg_autoneg_adver.s.advert_100base_tx_half =
486 reg_status.s.capable_100base_x_half;
487 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
488 CVMX_MDIO_PHY_REG_AUTONEG_ADVER,
489 reg_autoneg_adver.u16);
490 if (reg_status.s.capable_extended_status) {
491 reg_extended_status.u16 =
492 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
493 CVMX_MDIO_PHY_REG_EXTENDED_STATUS);
494 reg_control_1000.u16 =
495 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
496 CVMX_MDIO_PHY_REG_CONTROL_1000);
497 reg_control_1000.s.advert_1000base_t_full =
498 reg_extended_status.s.capable_1000base_t_full;
499 reg_control_1000.s.advert_1000base_t_half =
500 reg_extended_status.s.capable_1000base_t_half;
501 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
502 CVMX_MDIO_PHY_REG_CONTROL_1000,
503 reg_control_1000.u16);
504 }
505 reg_control.u16 =
506 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
507 CVMX_MDIO_PHY_REG_CONTROL);
508 reg_control.s.autoneg_enable = 1;
509 reg_control.s.restart_autoneg = 1;
510 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
511 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
512 } else if ((link_flags & set_phy_link_flags_autoneg)) {
513 cvmx_mdio_phy_reg_control_t reg_control;
514 cvmx_mdio_phy_reg_status_t reg_status;
515 cvmx_mdio_phy_reg_autoneg_adver_t reg_autoneg_adver;
516 cvmx_mdio_phy_reg_control_1000_t reg_control_1000;
517
518 reg_status.u16 =
519 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
520 CVMX_MDIO_PHY_REG_STATUS);
521 reg_autoneg_adver.u16 =
522 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
523 CVMX_MDIO_PHY_REG_AUTONEG_ADVER);
524 reg_autoneg_adver.s.advert_100base_t4 = 0;
525 reg_autoneg_adver.s.advert_10base_tx_full = 0;
526 reg_autoneg_adver.s.advert_10base_tx_half = 0;
527 reg_autoneg_adver.s.advert_100base_tx_full = 0;
528 reg_autoneg_adver.s.advert_100base_tx_half = 0;
529 if (reg_status.s.capable_extended_status) {
530 reg_control_1000.u16 =
531 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
532 CVMX_MDIO_PHY_REG_CONTROL_1000);
533 reg_control_1000.s.advert_1000base_t_full = 0;
534 reg_control_1000.s.advert_1000base_t_half = 0;
535 }
536 switch (link_info.s.speed) {
537 case 10:
538 reg_autoneg_adver.s.advert_10base_tx_full =
539 link_info.s.full_duplex;
540 reg_autoneg_adver.s.advert_10base_tx_half =
541 !link_info.s.full_duplex;
542 break;
543 case 100:
544 reg_autoneg_adver.s.advert_100base_tx_full =
545 link_info.s.full_duplex;
546 reg_autoneg_adver.s.advert_100base_tx_half =
547 !link_info.s.full_duplex;
548 break;
549 case 1000:
550 reg_control_1000.s.advert_1000base_t_full =
551 link_info.s.full_duplex;
552 reg_control_1000.s.advert_1000base_t_half =
553 !link_info.s.full_duplex;
554 break;
555 }
556 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
557 CVMX_MDIO_PHY_REG_AUTONEG_ADVER,
558 reg_autoneg_adver.u16);
559 if (reg_status.s.capable_extended_status)
560 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
561 CVMX_MDIO_PHY_REG_CONTROL_1000,
562 reg_control_1000.u16);
563 reg_control.u16 =
564 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
565 CVMX_MDIO_PHY_REG_CONTROL);
566 reg_control.s.autoneg_enable = 1;
567 reg_control.s.restart_autoneg = 1;
568 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
569 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
570 } else {
571 cvmx_mdio_phy_reg_control_t reg_control;
572 reg_control.u16 =
573 cvmx_mdio_read(phy_addr >> 8, phy_addr & 0xff,
574 CVMX_MDIO_PHY_REG_CONTROL);
575 reg_control.s.autoneg_enable = 0;
576 reg_control.s.restart_autoneg = 1;
577 reg_control.s.duplex = link_info.s.full_duplex;
578 if (link_info.s.speed == 1000) {
579 reg_control.s.speed_msb = 1;
580 reg_control.s.speed_lsb = 0;
581 } else if (link_info.s.speed == 100) {
582 reg_control.s.speed_msb = 0;
583 reg_control.s.speed_lsb = 1;
584 } else if (link_info.s.speed == 10) {
585 reg_control.s.speed_msb = 0;
586 reg_control.s.speed_lsb = 0;
587 }
588 cvmx_mdio_write(phy_addr >> 8, phy_addr & 0xff,
589 CVMX_MDIO_PHY_REG_CONTROL, reg_control.u16);
590 }
591 return 0;
592}
593
594/**
595 * This function is called by cvmx_helper_interface_probe() after it
596 * determines the number of ports Octeon can support on a specific
597 * interface. This function is the per board location to override
598 * this value. It is called with the number of ports Octeon might
599 * support and should return the number of actual ports on the
600 * board.
601 *
602 * This function must be modifed for every new Octeon board.
603 * Internally it uses switch statements based on the cvmx_sysinfo
604 * data to determine board types and revisions. It relys on the
605 * fact that every Octeon board receives a unique board type
606 * enumeration from the bootloader.
607 *
608 * @interface: Interface to probe
609 * @supported_ports:
610 * Number of ports Octeon supports.
611 *
612 * Returns Number of ports the actual board supports. Many times this will
613 * simple be "support_ports".
614 */
615int __cvmx_helper_board_interface_probe(int interface, int supported_ports)
616{
617 switch (cvmx_sysinfo_get()->board_type) {
618 case CVMX_BOARD_TYPE_CN3005_EVB_HS5:
619 if (interface == 0)
620 return 2;
621 break;
622 case CVMX_BOARD_TYPE_BBGW_REF:
623 if (interface == 0)
624 return 2;
625 break;
626 case CVMX_BOARD_TYPE_NIC_XLE_4G:
627 if (interface == 0)
628 return 0;
629 break;
630 /* The 2nd interface on the EBH5600 is connected to the Marvel switch,
631 which we don't support. Disable ports connected to it */
632 case CVMX_BOARD_TYPE_EBH5600:
633 if (interface == 1)
634 return 0;
635 break;
636 }
637 return supported_ports;
638}
639
640/**
641 * Enable packet input/output from the hardware. This function is
642 * called after by cvmx_helper_packet_hardware_enable() to
643 * perform board specific initialization. For most boards
644 * nothing is needed.
645 *
646 * @interface: Interface to enable
647 *
648 * Returns Zero on success, negative on failure
649 */
650int __cvmx_helper_board_hardware_enable(int interface)
651{
652 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_CN3005_EVB_HS5) {
653 if (interface == 0) {
654 /* Different config for switch port */
655 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(1, interface), 0);
656 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(1, interface), 0);
657 /*
658 * Boards with gigabit WAN ports need a
659 * different setting that is compatible with
660 * 100 Mbit settings
661 */
662 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX(0, interface),
663 0xc);
664 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX(0, interface),
665 0xc);
666 }
667 } else if (cvmx_sysinfo_get()->board_type ==
668 CVMX_BOARD_TYPE_CN3010_EVB_HS5) {
669 /*
670 * Broadcom PHYs require differnet ASX
671 * clocks. Unfortunately many boards don't define a
672 * new board Id and simply mangle the
673 * CN3010_EVB_HS5
674 */
675 if (interface == 0) {
676 /*
677 * Some boards use a hacked up bootloader that
678 * identifies them as CN3010_EVB_HS5
679 * evaluation boards. This leads to all kinds
680 * of configuration problems. Detect one
681 * case, and print warning, while trying to do
682 * the right thing.
683 */
684 int phy_addr = cvmx_helper_board_get_mii_address(0);
685 if (phy_addr != -1) {
686 int phy_identifier =
687 cvmx_mdio_read(phy_addr >> 8,
688 phy_addr & 0xff, 0x2);
689 /* Is it a Broadcom PHY? */
690 if (phy_identifier == 0x0143) {
691 cvmx_dprintf("\n");
692 cvmx_dprintf("ERROR:\n");
693 cvmx_dprintf
694 ("ERROR: Board type is CVMX_BOARD_TYPE_CN3010_EVB_HS5, but Broadcom PHY found.\n");
695 cvmx_dprintf
696 ("ERROR: The board type is mis-configured, and software malfunctions are likely.\n");
697 cvmx_dprintf
698 ("ERROR: All boards require a unique board type to identify them.\n");
699 cvmx_dprintf("ERROR:\n");
700 cvmx_dprintf("\n");
701 cvmx_wait(1000000000);
702 cvmx_write_csr(CVMX_ASXX_RX_CLK_SETX
703 (0, interface), 5);
704 cvmx_write_csr(CVMX_ASXX_TX_CLK_SETX
705 (0, interface), 5);
706 }
707 }
708 }
709 }
710 return 0;
711}
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 00000000000..c239e5f4ab9
--- /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 00000000000..bfbd46115e7
--- /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 00000000000..cc94cfa545b
--- /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 00000000000..82b21843421
--- /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 00000000000..0c0bf5d30e7
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c
@@ -0,0 +1,554 @@
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
329int __cvmx_helper_sgmii_enumerate(int interface)
330{
331 return 4;
332}
333/**
334 * Probe a SGMII interface and determine the number of ports
335 * connected to it. The SGMII interface should still be down after
336 * this call.
337 *
338 * @interface: Interface to probe
339 *
340 * Returns Number of ports on the interface. Zero to disable.
341 */
342int __cvmx_helper_sgmii_probe(int interface)
343{
344 union cvmx_gmxx_inf_mode mode;
345
346 /*
347 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
348 * interface needs to be enabled before IPD otherwise per port
349 * backpressure may not work properly
350 */
351 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
352 mode.s.en = 1;
353 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
354 return __cvmx_helper_sgmii_enumerate(interface);
355}
356
357/**
358 * Bringup and enable a SGMII interface. After this call packet
359 * I/O should be fully functional. This is called with IPD
360 * enabled but PKO disabled.
361 *
362 * @interface: Interface to bring up
363 *
364 * Returns Zero on success, negative on failure
365 */
366int __cvmx_helper_sgmii_enable(int interface)
367{
368 int num_ports = cvmx_helper_ports_on_interface(interface);
369 int index;
370
371 __cvmx_helper_sgmii_hardware_init(interface, num_ports);
372
373 for (index = 0; index < num_ports; index++) {
374 union cvmx_gmxx_prtx_cfg gmxx_prtx_cfg;
375 gmxx_prtx_cfg.u64 =
376 cvmx_read_csr(CVMX_GMXX_PRTX_CFG(index, interface));
377 gmxx_prtx_cfg.s.en = 1;
378 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(index, interface),
379 gmxx_prtx_cfg.u64);
380 __cvmx_interrupt_pcsx_intx_en_reg_enable(index, interface);
381 }
382 __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
383 __cvmx_interrupt_gmxx_enable(interface);
384 return 0;
385}
386
387/**
388 * Return the link state of an IPD/PKO port as returned by
389 * auto negotiation. The result of this function may not match
390 * Octeon's link config if auto negotiation has changed since
391 * the last call to cvmx_helper_link_set().
392 *
393 * @ipd_port: IPD/PKO port to query
394 *
395 * Returns Link state
396 */
397cvmx_helper_link_info_t __cvmx_helper_sgmii_link_get(int ipd_port)
398{
399 cvmx_helper_link_info_t result;
400 union cvmx_pcsx_miscx_ctl_reg pcs_misc_ctl_reg;
401 int interface = cvmx_helper_get_interface_num(ipd_port);
402 int index = cvmx_helper_get_interface_index_num(ipd_port);
403 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
404
405 result.u64 = 0;
406
407 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
408 /* The simulator gives you a simulated 1Gbps full duplex link */
409 result.s.link_up = 1;
410 result.s.full_duplex = 1;
411 result.s.speed = 1000;
412 return result;
413 }
414
415 pcsx_mrx_control_reg.u64 =
416 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
417 if (pcsx_mrx_control_reg.s.loopbck1) {
418 /* Force 1Gbps full duplex link for internal loopback */
419 result.s.link_up = 1;
420 result.s.full_duplex = 1;
421 result.s.speed = 1000;
422 return result;
423 }
424
425 pcs_misc_ctl_reg.u64 =
426 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
427 if (pcs_misc_ctl_reg.s.mode) {
428 /* 1000BASE-X */
429 /* FIXME */
430 } else {
431 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
432 pcsx_miscx_ctl_reg.u64 =
433 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
434 if (pcsx_miscx_ctl_reg.s.mac_phy) {
435 /* PHY Mode */
436 union cvmx_pcsx_mrx_status_reg pcsx_mrx_status_reg;
437 union cvmx_pcsx_anx_results_reg pcsx_anx_results_reg;
438
439 /*
440 * Don't bother continuing if the SERTES low
441 * level link is down
442 */
443 pcsx_mrx_status_reg.u64 =
444 cvmx_read_csr(CVMX_PCSX_MRX_STATUS_REG
445 (index, interface));
446 if (pcsx_mrx_status_reg.s.lnk_st == 0) {
447 if (__cvmx_helper_sgmii_hardware_init_link
448 (interface, index) != 0)
449 return result;
450 }
451
452 /* Read the autoneg results */
453 pcsx_anx_results_reg.u64 =
454 cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG
455 (index, interface));
456 if (pcsx_anx_results_reg.s.an_cpt) {
457 /*
458 * Auto negotiation is complete. Set
459 * status accordingly.
460 */
461 result.s.full_duplex =
462 pcsx_anx_results_reg.s.dup;
463 result.s.link_up =
464 pcsx_anx_results_reg.s.link_ok;
465 switch (pcsx_anx_results_reg.s.spd) {
466 case 0:
467 result.s.speed = 10;
468 break;
469 case 1:
470 result.s.speed = 100;
471 break;
472 case 2:
473 result.s.speed = 1000;
474 break;
475 default:
476 result.s.speed = 0;
477 result.s.link_up = 0;
478 break;
479 }
480 } else {
481 /*
482 * Auto negotiation isn't
483 * complete. Return link down.
484 */
485 result.s.speed = 0;
486 result.s.link_up = 0;
487 }
488 } else { /* MAC Mode */
489
490 result = __cvmx_helper_board_link_get(ipd_port);
491 }
492 }
493 return result;
494}
495
496/**
497 * Configure an IPD/PKO port for the specified link state. This
498 * function does not influence auto negotiation at the PHY level.
499 * The passed link state must always match the link state returned
500 * by cvmx_helper_link_get(). It is normally best to use
501 * cvmx_helper_link_autoconf() instead.
502 *
503 * @ipd_port: IPD/PKO port to configure
504 * @link_info: The new link state
505 *
506 * Returns Zero on success, negative on failure
507 */
508int __cvmx_helper_sgmii_link_set(int ipd_port,
509 cvmx_helper_link_info_t link_info)
510{
511 int interface = cvmx_helper_get_interface_num(ipd_port);
512 int index = cvmx_helper_get_interface_index_num(ipd_port);
513 __cvmx_helper_sgmii_hardware_init_link(interface, index);
514 return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index,
515 link_info);
516}
517
518/**
519 * Configure a port for internal and/or external loopback. Internal
520 * loopback causes packets sent by the port to be received by
521 * Octeon. External loopback causes packets received from the wire to
522 * sent out again.
523 *
524 * @ipd_port: IPD/PKO port to loopback.
525 * @enable_internal:
526 * Non zero if you want internal loopback
527 * @enable_external:
528 * Non zero if you want external loopback
529 *
530 * Returns Zero on success, negative on failure.
531 */
532int __cvmx_helper_sgmii_configure_loopback(int ipd_port, int enable_internal,
533 int enable_external)
534{
535 int interface = cvmx_helper_get_interface_num(ipd_port);
536 int index = cvmx_helper_get_interface_index_num(ipd_port);
537 union cvmx_pcsx_mrx_control_reg pcsx_mrx_control_reg;
538 union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg;
539
540 pcsx_mrx_control_reg.u64 =
541 cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface));
542 pcsx_mrx_control_reg.s.loopbck1 = enable_internal;
543 cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface),
544 pcsx_mrx_control_reg.u64);
545
546 pcsx_miscx_ctl_reg.u64 =
547 cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface));
548 pcsx_miscx_ctl_reg.s.loopbck2 = enable_external;
549 cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface),
550 pcsx_miscx_ctl_reg.u64);
551
552 __cvmx_helper_sgmii_hardware_init_link(interface, index);
553 return 0;
554}
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 00000000000..2830e4bdf7f
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-spi.c
@@ -0,0 +1,205 @@
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
54int __cvmx_helper_spi_enumerate(int interface)
55{
56 if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
57 cvmx_spi4000_is_present(interface)) {
58 return 10;
59 } else {
60 return 16;
61 }
62}
63
64/**
65 * Probe a SPI interface and determine the number of ports
66 * connected to it. The SPI interface should still be down after
67 * this call.
68 *
69 * @interface: Interface to probe
70 *
71 * Returns Number of ports on the interface. Zero to disable.
72 */
73int __cvmx_helper_spi_probe(int interface)
74{
75 int num_ports = 0;
76
77 if ((cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) &&
78 cvmx_spi4000_is_present(interface)) {
79 num_ports = 10;
80 } else {
81 union cvmx_pko_reg_crc_enable enable;
82 num_ports = 16;
83 /*
84 * Unlike the SPI4000, most SPI devices don't
85 * automatically put on the L2 CRC. For everything
86 * except for the SPI4000 have PKO append the L2 CRC
87 * to the packet.
88 */
89 enable.u64 = cvmx_read_csr(CVMX_PKO_REG_CRC_ENABLE);
90 enable.s.enable |= 0xffff << (interface * 16);
91 cvmx_write_csr(CVMX_PKO_REG_CRC_ENABLE, enable.u64);
92 }
93 __cvmx_helper_setup_gmx(interface, num_ports);
94 return num_ports;
95}
96
97/**
98 * Bringup and enable a SPI interface. After this call packet I/O
99 * should be fully functional. This is called with IPD enabled but
100 * PKO disabled.
101 *
102 * @interface: Interface to bring up
103 *
104 * Returns Zero on success, negative on failure
105 */
106int __cvmx_helper_spi_enable(int interface)
107{
108 /*
109 * Normally the ethernet L2 CRC is checked and stripped in the
110 * GMX block. When you are using SPI, this isn' the case and
111 * IPD needs to check the L2 CRC.
112 */
113 int num_ports = cvmx_helper_ports_on_interface(interface);
114 int ipd_port;
115 for (ipd_port = interface * 16; ipd_port < interface * 16 + num_ports;
116 ipd_port++) {
117 union cvmx_pip_prt_cfgx port_config;
118 port_config.u64 = cvmx_read_csr(CVMX_PIP_PRT_CFGX(ipd_port));
119 port_config.s.crc_en = 1;
120 cvmx_write_csr(CVMX_PIP_PRT_CFGX(ipd_port), port_config.u64);
121 }
122
123 if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) {
124 cvmx_spi_start_interface(interface, CVMX_SPI_MODE_DUPLEX,
125 CVMX_HELPER_SPI_TIMEOUT, num_ports);
126 if (cvmx_spi4000_is_present(interface))
127 cvmx_spi4000_initialize(interface);
128 }
129 __cvmx_interrupt_spxx_int_msk_enable(interface);
130 __cvmx_interrupt_stxx_int_msk_enable(interface);
131 __cvmx_interrupt_gmxx_enable(interface);
132 return 0;
133}
134
135/**
136 * Return the link state of an IPD/PKO port as returned by
137 * auto negotiation. The result of this function may not match
138 * Octeon's link config if auto negotiation has changed since
139 * the last call to cvmx_helper_link_set().
140 *
141 * @ipd_port: IPD/PKO port to query
142 *
143 * Returns Link state
144 */
145cvmx_helper_link_info_t __cvmx_helper_spi_link_get(int ipd_port)
146{
147 cvmx_helper_link_info_t result;
148 int interface = cvmx_helper_get_interface_num(ipd_port);
149 int index = cvmx_helper_get_interface_index_num(ipd_port);
150 result.u64 = 0;
151
152 if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM) {
153 /* The simulator gives you a simulated full duplex link */
154 result.s.link_up = 1;
155 result.s.full_duplex = 1;
156 result.s.speed = 10000;
157 } else if (cvmx_spi4000_is_present(interface)) {
158 union cvmx_gmxx_rxx_rx_inbnd inband =
159 cvmx_spi4000_check_speed(interface, index);
160 result.s.link_up = inband.s.status;
161 result.s.full_duplex = inband.s.duplex;
162 switch (inband.s.speed) {
163 case 0: /* 10 Mbps */
164 result.s.speed = 10;
165 break;
166 case 1: /* 100 Mbps */
167 result.s.speed = 100;
168 break;
169 case 2: /* 1 Gbps */
170 result.s.speed = 1000;
171 break;
172 case 3: /* Illegal */
173 result.s.speed = 0;
174 result.s.link_up = 0;
175 break;
176 }
177 } else {
178 /* For generic SPI we can't determine the link, just return some
179 sane results */
180 result.s.link_up = 1;
181 result.s.full_duplex = 1;
182 result.s.speed = 10000;
183 }
184 return result;
185}
186
187/**
188 * Configure an IPD/PKO port for the specified link state. This
189 * function does not influence auto negotiation at the PHY level.
190 * The passed link state must always match the link state returned
191 * by cvmx_helper_link_get(). It is normally best to use
192 * cvmx_helper_link_autoconf() instead.
193 *
194 * @ipd_port: IPD/PKO port to configure
195 * @link_info: The new link state
196 *
197 * Returns Zero on success, negative on failure
198 */
199int __cvmx_helper_spi_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
200{
201 /* Nothing to do. If we have a SPI4000 then the setup was already performed
202 by cvmx_spi4000_check_speed(). If not then there isn't any link
203 info */
204 return 0;
205}
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 00000000000..116dea17acf
--- /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 00000000000..1723248e987
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c
@@ -0,0 +1,354 @@
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
48int __cvmx_helper_xaui_enumerate(int interface)
49{
50 union cvmx_gmxx_hg2_control gmx_hg2_control;
51
52 /* If HiGig2 is enabled return 16 ports, otherwise return 1 port */
53 gmx_hg2_control.u64 = cvmx_read_csr(CVMX_GMXX_HG2_CONTROL(interface));
54 if (gmx_hg2_control.s.hg2tx_en)
55 return 16;
56 else
57 return 1;
58}
59
60/**
61 * Probe a XAUI interface and determine the number of ports
62 * connected to it. The XAUI interface should still be down
63 * after this call.
64 *
65 * @interface: Interface to probe
66 *
67 * Returns Number of ports on the interface. Zero to disable.
68 */
69int __cvmx_helper_xaui_probe(int interface)
70{
71 int i;
72 union cvmx_gmxx_inf_mode mode;
73
74 /*
75 * Due to errata GMX-700 on CN56XXp1.x and CN52XXp1.x, the
76 * interface needs to be enabled before IPD otherwise per port
77 * backpressure may not work properly.
78 */
79 mode.u64 = cvmx_read_csr(CVMX_GMXX_INF_MODE(interface));
80 mode.s.en = 1;
81 cvmx_write_csr(CVMX_GMXX_INF_MODE(interface), mode.u64);
82
83 __cvmx_helper_setup_gmx(interface, 1);
84
85 /*
86 * Setup PKO to support 16 ports for HiGig2 virtual
87 * ports. We're pointing all of the PKO packet ports for this
88 * interface to the XAUI. This allows us to use HiGig2
89 * backpressure per port.
90 */
91 for (i = 0; i < 16; i++) {
92 union cvmx_pko_mem_port_ptrs pko_mem_port_ptrs;
93 pko_mem_port_ptrs.u64 = 0;
94 /*
95 * We set each PKO port to have equal priority in a
96 * round robin fashion.
97 */
98 pko_mem_port_ptrs.s.static_p = 0;
99 pko_mem_port_ptrs.s.qos_mask = 0xff;
100 /* All PKO ports map to the same XAUI hardware port */
101 pko_mem_port_ptrs.s.eid = interface * 4;
102 pko_mem_port_ptrs.s.pid = interface * 16 + i;
103 cvmx_write_csr(CVMX_PKO_MEM_PORT_PTRS, pko_mem_port_ptrs.u64);
104 }
105 return __cvmx_helper_xaui_enumerate(interface);
106}
107
108/**
109 * Bringup and enable a XAUI interface. After this call packet
110 * I/O should be fully functional. This is called with IPD
111 * enabled but PKO disabled.
112 *
113 * @interface: Interface to bring up
114 *
115 * Returns Zero on success, negative on failure
116 */
117int __cvmx_helper_xaui_enable(int interface)
118{
119 union cvmx_gmxx_prtx_cfg gmx_cfg;
120 union cvmx_pcsxx_control1_reg xauiCtl;
121 union cvmx_pcsxx_misc_ctl_reg xauiMiscCtl;
122 union cvmx_gmxx_tx_xaui_ctl gmxXauiTxCtl;
123 union cvmx_gmxx_rxx_int_en gmx_rx_int_en;
124 union cvmx_gmxx_tx_int_en gmx_tx_int_en;
125 union cvmx_pcsxx_int_en_reg pcsx_int_en_reg;
126
127 /* (1) Interface has already been enabled. */
128
129 /* (2) Disable GMX. */
130 xauiMiscCtl.u64 = cvmx_read_csr(CVMX_PCSXX_MISC_CTL_REG(interface));
131 xauiMiscCtl.s.gmxeno = 1;
132 cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
133
134 /* (3) Disable GMX and PCSX interrupts. */
135 gmx_rx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_RXX_INT_EN(0, interface));
136 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
137 gmx_tx_int_en.u64 = cvmx_read_csr(CVMX_GMXX_TX_INT_EN(interface));
138 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
139 pcsx_int_en_reg.u64 = cvmx_read_csr(CVMX_PCSXX_INT_EN_REG(interface));
140 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
141
142 /* (4) Bring up the PCSX and GMX reconciliation layer. */
143 /* (4)a Set polarity and lane swapping. */
144 /* (4)b */
145 gmxXauiTxCtl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
146 /* Enable better IFG packing and improves performance */
147 gmxXauiTxCtl.s.dic_en = 1;
148 gmxXauiTxCtl.s.uni_en = 0;
149 cvmx_write_csr(CVMX_GMXX_TX_XAUI_CTL(interface), gmxXauiTxCtl.u64);
150
151 /* (4)c Aply reset sequence */
152 xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
153 xauiCtl.s.lo_pwr = 0;
154 xauiCtl.s.reset = 1;
155 cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64);
156
157 /* Wait for PCS to come out of reset */
158 if (CVMX_WAIT_FOR_FIELD64
159 (CVMX_PCSXX_CONTROL1_REG(interface), union cvmx_pcsxx_control1_reg,
160 reset, ==, 0, 10000))
161 return -1;
162 /* Wait for PCS to be aligned */
163 if (CVMX_WAIT_FOR_FIELD64
164 (CVMX_PCSXX_10GBX_STATUS_REG(interface),
165 union cvmx_pcsxx_10gbx_status_reg, alignd, ==, 1, 10000))
166 return -1;
167 /* Wait for RX to be ready */
168 if (CVMX_WAIT_FOR_FIELD64
169 (CVMX_GMXX_RX_XAUI_CTL(interface), union cvmx_gmxx_rx_xaui_ctl,
170 status, ==, 0, 10000))
171 return -1;
172
173 /* (6) Configure GMX */
174 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
175 gmx_cfg.s.en = 0;
176 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
177
178 /* Wait for GMX RX to be idle */
179 if (CVMX_WAIT_FOR_FIELD64
180 (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
181 rx_idle, ==, 1, 10000))
182 return -1;
183 /* Wait for GMX TX to be idle */
184 if (CVMX_WAIT_FOR_FIELD64
185 (CVMX_GMXX_PRTX_CFG(0, interface), union cvmx_gmxx_prtx_cfg,
186 tx_idle, ==, 1, 10000))
187 return -1;
188
189 /* GMX configure */
190 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
191 gmx_cfg.s.speed = 1;
192 gmx_cfg.s.speed_msb = 0;
193 gmx_cfg.s.slottime = 1;
194 cvmx_write_csr(CVMX_GMXX_TX_PRTS(interface), 1);
195 cvmx_write_csr(CVMX_GMXX_TXX_SLOT(0, interface), 512);
196 cvmx_write_csr(CVMX_GMXX_TXX_BURST(0, interface), 8192);
197 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
198
199 /* (7) Clear out any error state */
200 cvmx_write_csr(CVMX_GMXX_RXX_INT_REG(0, interface),
201 cvmx_read_csr(CVMX_GMXX_RXX_INT_REG(0, interface)));
202 cvmx_write_csr(CVMX_GMXX_TX_INT_REG(interface),
203 cvmx_read_csr(CVMX_GMXX_TX_INT_REG(interface)));
204 cvmx_write_csr(CVMX_PCSXX_INT_REG(interface),
205 cvmx_read_csr(CVMX_PCSXX_INT_REG(interface)));
206
207 /* Wait for receive link */
208 if (CVMX_WAIT_FOR_FIELD64
209 (CVMX_PCSXX_STATUS1_REG(interface), union cvmx_pcsxx_status1_reg,
210 rcv_lnk, ==, 1, 10000))
211 return -1;
212 if (CVMX_WAIT_FOR_FIELD64
213 (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
214 xmtflt, ==, 0, 10000))
215 return -1;
216 if (CVMX_WAIT_FOR_FIELD64
217 (CVMX_PCSXX_STATUS2_REG(interface), union cvmx_pcsxx_status2_reg,
218 rcvflt, ==, 0, 10000))
219 return -1;
220
221 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), gmx_rx_int_en.u64);
222 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), gmx_tx_int_en.u64);
223 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), pcsx_int_en_reg.u64);
224
225 cvmx_helper_link_autoconf(cvmx_helper_get_ipd_port(interface, 0));
226
227 /* (8) Enable packet reception */
228 xauiMiscCtl.s.gmxeno = 0;
229 cvmx_write_csr(CVMX_PCSXX_MISC_CTL_REG(interface), xauiMiscCtl.u64);
230
231 gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface));
232 gmx_cfg.s.en = 1;
233 cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64);
234
235 __cvmx_interrupt_pcsx_intx_en_reg_enable(0, interface);
236 __cvmx_interrupt_pcsx_intx_en_reg_enable(1, interface);
237 __cvmx_interrupt_pcsx_intx_en_reg_enable(2, interface);
238 __cvmx_interrupt_pcsx_intx_en_reg_enable(3, interface);
239 __cvmx_interrupt_pcsxx_int_en_reg_enable(interface);
240 __cvmx_interrupt_gmxx_enable(interface);
241
242 return 0;
243}
244
245/**
246 * Return the link state of an IPD/PKO port as returned by
247 * auto negotiation. The result of this function may not match
248 * Octeon's link config if auto negotiation has changed since
249 * the last call to cvmx_helper_link_set().
250 *
251 * @ipd_port: IPD/PKO port to query
252 *
253 * Returns Link state
254 */
255cvmx_helper_link_info_t __cvmx_helper_xaui_link_get(int ipd_port)
256{
257 int interface = cvmx_helper_get_interface_num(ipd_port);
258 union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
259 union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
260 union cvmx_pcsxx_status1_reg pcsxx_status1_reg;
261 cvmx_helper_link_info_t result;
262
263 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
264 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
265 pcsxx_status1_reg.u64 =
266 cvmx_read_csr(CVMX_PCSXX_STATUS1_REG(interface));
267 result.u64 = 0;
268
269 /* Only return a link if both RX and TX are happy */
270 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0) &&
271 (pcsxx_status1_reg.s.rcv_lnk == 1)) {
272 result.s.link_up = 1;
273 result.s.full_duplex = 1;
274 result.s.speed = 10000;
275 } else {
276 /* Disable GMX and PCSX interrupts. */
277 cvmx_write_csr(CVMX_GMXX_RXX_INT_EN(0, interface), 0x0);
278 cvmx_write_csr(CVMX_GMXX_TX_INT_EN(interface), 0x0);
279 cvmx_write_csr(CVMX_PCSXX_INT_EN_REG(interface), 0x0);
280 }
281 return result;
282}
283
284/**
285 * Configure an IPD/PKO port for the specified link state. This
286 * function does not influence auto negotiation at the PHY level.
287 * The passed link state must always match the link state returned
288 * by cvmx_helper_link_get(). It is normally best to use
289 * cvmx_helper_link_autoconf() instead.
290 *
291 * @ipd_port: IPD/PKO port to configure
292 * @link_info: The new link state
293 *
294 * Returns Zero on success, negative on failure
295 */
296int __cvmx_helper_xaui_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
297{
298 int interface = cvmx_helper_get_interface_num(ipd_port);
299 union cvmx_gmxx_tx_xaui_ctl gmxx_tx_xaui_ctl;
300 union cvmx_gmxx_rx_xaui_ctl gmxx_rx_xaui_ctl;
301
302 gmxx_tx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_TX_XAUI_CTL(interface));
303 gmxx_rx_xaui_ctl.u64 = cvmx_read_csr(CVMX_GMXX_RX_XAUI_CTL(interface));
304
305 /* If the link shouldn't be up, then just return */
306 if (!link_info.s.link_up)
307 return 0;
308
309 /* Do nothing if both RX and TX are happy */
310 if ((gmxx_tx_xaui_ctl.s.ls == 0) && (gmxx_rx_xaui_ctl.s.status == 0))
311 return 0;
312
313 /* Bring the link up */
314 return __cvmx_helper_xaui_enable(interface);
315}
316
317/**
318 * Configure a port for internal and/or external loopback. Internal loopback
319 * causes packets sent by the port to be received by Octeon. External loopback
320 * causes packets received from the wire to sent out again.
321 *
322 * @ipd_port: IPD/PKO port to loopback.
323 * @enable_internal:
324 * Non zero if you want internal loopback
325 * @enable_external:
326 * Non zero if you want external loopback
327 *
328 * Returns Zero on success, negative on failure.
329 */
330extern int __cvmx_helper_xaui_configure_loopback(int ipd_port,
331 int enable_internal,
332 int enable_external)
333{
334 int interface = cvmx_helper_get_interface_num(ipd_port);
335 union cvmx_pcsxx_control1_reg pcsxx_control1_reg;
336 union cvmx_gmxx_xaui_ext_loopback gmxx_xaui_ext_loopback;
337
338 /* Set the internal loop */
339 pcsxx_control1_reg.u64 =
340 cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface));
341 pcsxx_control1_reg.s.loopbck1 = enable_internal;
342 cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface),
343 pcsxx_control1_reg.u64);
344
345 /* Set the external loop */
346 gmxx_xaui_ext_loopback.u64 =
347 cvmx_read_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface));
348 gmxx_xaui_ext_loopback.s.en = enable_external;
349 cvmx_write_csr(CVMX_GMXX_XAUI_EXT_LOOPBACK(interface),
350 gmxx_xaui_ext_loopback.u64);
351
352 /* Take the link through a reset */
353 return __cvmx_helper_xaui_enable(interface);
354}
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 00000000000..fa496385635
--- /dev/null
+++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c
@@ -0,0 +1,1116 @@
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 sets the interface_port_count[interface] correctly,
238 * without modifying any hardware configuration. Hardware setup of
239 * the ports will be performed later.
240 *
241 * @interface: Interface to probe
242 *
243 * Returns Zero on success, negative on failure
244 */
245int cvmx_helper_interface_enumerate(int interface)
246{
247 switch (cvmx_helper_interface_get_mode(interface)) {
248 /* These types don't support ports to IPD/PKO */
249 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
250 case CVMX_HELPER_INTERFACE_MODE_PCIE:
251 interface_port_count[interface] = 0;
252 break;
253 /* XAUI is a single high speed port */
254 case CVMX_HELPER_INTERFACE_MODE_XAUI:
255 interface_port_count[interface] =
256 __cvmx_helper_xaui_enumerate(interface);
257 break;
258 /*
259 * RGMII/GMII/MII are all treated about the same. Most
260 * functions refer to these ports as RGMII.
261 */
262 case CVMX_HELPER_INTERFACE_MODE_RGMII:
263 case CVMX_HELPER_INTERFACE_MODE_GMII:
264 interface_port_count[interface] =
265 __cvmx_helper_rgmii_enumerate(interface);
266 break;
267 /*
268 * SPI4 can have 1-16 ports depending on the device at
269 * the other end.
270 */
271 case CVMX_HELPER_INTERFACE_MODE_SPI:
272 interface_port_count[interface] =
273 __cvmx_helper_spi_enumerate(interface);
274 break;
275 /*
276 * SGMII can have 1-4 ports depending on how many are
277 * hooked up.
278 */
279 case CVMX_HELPER_INTERFACE_MODE_SGMII:
280 case CVMX_HELPER_INTERFACE_MODE_PICMG:
281 interface_port_count[interface] =
282 __cvmx_helper_sgmii_enumerate(interface);
283 break;
284 /* PCI target Network Packet Interface */
285 case CVMX_HELPER_INTERFACE_MODE_NPI:
286 interface_port_count[interface] =
287 __cvmx_helper_npi_enumerate(interface);
288 break;
289 /*
290 * Special loopback only ports. These are not the same
291 * as other ports in loopback mode.
292 */
293 case CVMX_HELPER_INTERFACE_MODE_LOOP:
294 interface_port_count[interface] =
295 __cvmx_helper_loop_enumerate(interface);
296 break;
297 }
298
299 interface_port_count[interface] =
300 __cvmx_helper_board_interface_probe(interface,
301 interface_port_count
302 [interface]);
303
304 /* Make sure all global variables propagate to other cores */
305 CVMX_SYNCWS;
306
307 return 0;
308}
309
310/**
311 * This function probes an interface to determine the actual
312 * number of hardware ports connected to it. It doesn't setup the
313 * ports or enable them. The main goal here is to set the global
314 * interface_port_count[interface] correctly. Hardware setup of the
315 * ports will be performed later.
316 *
317 * @interface: Interface to probe
318 *
319 * Returns Zero on success, negative on failure
320 */
321int cvmx_helper_interface_probe(int interface)
322{
323 cvmx_helper_interface_enumerate(interface);
324 /* At this stage in the game we don't want packets to be moving yet.
325 The following probe calls should perform hardware setup
326 needed to determine port counts. Receive must still be disabled */
327 switch (cvmx_helper_interface_get_mode(interface)) {
328 /* These types don't support ports to IPD/PKO */
329 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
330 case CVMX_HELPER_INTERFACE_MODE_PCIE:
331 break;
332 /* XAUI is a single high speed port */
333 case CVMX_HELPER_INTERFACE_MODE_XAUI:
334 __cvmx_helper_xaui_probe(interface);
335 break;
336 /*
337 * RGMII/GMII/MII are all treated about the same. Most
338 * functions refer to these ports as RGMII.
339 */
340 case CVMX_HELPER_INTERFACE_MODE_RGMII:
341 case CVMX_HELPER_INTERFACE_MODE_GMII:
342 __cvmx_helper_rgmii_probe(interface);
343 break;
344 /*
345 * SPI4 can have 1-16 ports depending on the device at
346 * the other end.
347 */
348 case CVMX_HELPER_INTERFACE_MODE_SPI:
349 __cvmx_helper_spi_probe(interface);
350 break;
351 /*
352 * SGMII can have 1-4 ports depending on how many are
353 * hooked up.
354 */
355 case CVMX_HELPER_INTERFACE_MODE_SGMII:
356 case CVMX_HELPER_INTERFACE_MODE_PICMG:
357 __cvmx_helper_sgmii_probe(interface);
358 break;
359 /* PCI target Network Packet Interface */
360 case CVMX_HELPER_INTERFACE_MODE_NPI:
361 __cvmx_helper_npi_probe(interface);
362 break;
363 /*
364 * Special loopback only ports. These are not the same
365 * as other ports in loopback mode.
366 */
367 case CVMX_HELPER_INTERFACE_MODE_LOOP:
368 __cvmx_helper_loop_probe(interface);
369 break;
370 }
371
372 /* Make sure all global variables propagate to other cores */
373 CVMX_SYNCWS;
374
375 return 0;
376}
377
378/**
379 * Setup the IPD/PIP for the ports on an interface. Packet
380 * classification and tagging are set for every port on the
381 * interface. The number of ports on the interface must already
382 * have been probed.
383 *
384 * @interface: Interface to setup IPD/PIP for
385 *
386 * Returns Zero on success, negative on failure
387 */
388static int __cvmx_helper_interface_setup_ipd(int interface)
389{
390 int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
391 int num_ports = interface_port_count[interface];
392
393 while (num_ports--) {
394 __cvmx_helper_port_setup_ipd(ipd_port);
395 ipd_port++;
396 }
397 return 0;
398}
399
400/**
401 * Setup global setting for IPD/PIP not related to a specific
402 * interface or port. This must be called before IPD is enabled.
403 *
404 * Returns Zero on success, negative on failure.
405 */
406static int __cvmx_helper_global_setup_ipd(void)
407{
408 /* Setup the global packet input options */
409 cvmx_ipd_config(CVMX_FPA_PACKET_POOL_SIZE / 8,
410 CVMX_HELPER_FIRST_MBUFF_SKIP / 8,
411 CVMX_HELPER_NOT_FIRST_MBUFF_SKIP / 8,
412 /* The +8 is to account for the next ptr */
413 (CVMX_HELPER_FIRST_MBUFF_SKIP + 8) / 128,
414 /* The +8 is to account for the next ptr */
415 (CVMX_HELPER_NOT_FIRST_MBUFF_SKIP + 8) / 128,
416 CVMX_FPA_WQE_POOL,
417 CVMX_IPD_OPC_MODE_STT,
418 CVMX_HELPER_ENABLE_BACK_PRESSURE);
419 return 0;
420}
421
422/**
423 * Setup the PKO for the ports on an interface. The number of
424 * queues per port and the priority of each PKO output queue
425 * is set here. PKO must be disabled when this function is called.
426 *
427 * @interface: Interface to setup PKO for
428 *
429 * Returns Zero on success, negative on failure
430 */
431static int __cvmx_helper_interface_setup_pko(int interface)
432{
433 /*
434 * Each packet output queue has an associated priority. The
435 * higher the priority, the more often it can send a packet. A
436 * priority of 8 means it can send in all 8 rounds of
437 * contention. We're going to make each queue one less than
438 * the last. The vector of priorities has been extended to
439 * support CN5xxx CPUs, where up to 16 queues can be
440 * associated to a port. To keep backward compatibility we
441 * don't change the initial 8 priorities and replicate them in
442 * the second half. With per-core PKO queues (PKO lockless
443 * operation) all queues have the same priority.
444 */
445 uint64_t priorities[16] =
446 { 8, 7, 6, 5, 4, 3, 2, 1, 8, 7, 6, 5, 4, 3, 2, 1 };
447
448 /*
449 * Setup the IPD/PIP and PKO for the ports discovered
450 * above. Here packet classification, tagging and output
451 * priorities are set.
452 */
453 int ipd_port = cvmx_helper_get_ipd_port(interface, 0);
454 int num_ports = interface_port_count[interface];
455 while (num_ports--) {
456 /*
457 * Give the user a chance to override the per queue
458 * priorities.
459 */
460 if (cvmx_override_pko_queue_priority)
461 cvmx_override_pko_queue_priority(ipd_port, priorities);
462
463 cvmx_pko_config_port(ipd_port,
464 cvmx_pko_get_base_queue_per_core(ipd_port,
465 0),
466 cvmx_pko_get_num_queues(ipd_port),
467 priorities);
468 ipd_port++;
469 }
470 return 0;
471}
472
473/**
474 * Setup global setting for PKO not related to a specific
475 * interface or port. This must be called before PKO is enabled.
476 *
477 * Returns Zero on success, negative on failure.
478 */
479static int __cvmx_helper_global_setup_pko(void)
480{
481 /*
482 * Disable tagwait FAU timeout. This needs to be done before
483 * anyone might start packet output using tags.
484 */
485 union cvmx_iob_fau_timeout fau_to;
486 fau_to.u64 = 0;
487 fau_to.s.tout_val = 0xfff;
488 fau_to.s.tout_enb = 0;
489 cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64);
490 return 0;
491}
492
493/**
494 * Setup global backpressure setting.
495 *
496 * Returns Zero on success, negative on failure
497 */
498static int __cvmx_helper_global_setup_backpressure(void)
499{
500#if CVMX_HELPER_DISABLE_RGMII_BACKPRESSURE
501 /* Disable backpressure if configured to do so */
502 /* Disable backpressure (pause frame) generation */
503 int num_interfaces = cvmx_helper_get_number_of_interfaces();
504 int interface;
505 for (interface = 0; interface < num_interfaces; interface++) {
506 switch (cvmx_helper_interface_get_mode(interface)) {
507 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
508 case CVMX_HELPER_INTERFACE_MODE_PCIE:
509 case CVMX_HELPER_INTERFACE_MODE_NPI:
510 case CVMX_HELPER_INTERFACE_MODE_LOOP:
511 case CVMX_HELPER_INTERFACE_MODE_XAUI:
512 break;
513 case CVMX_HELPER_INTERFACE_MODE_RGMII:
514 case CVMX_HELPER_INTERFACE_MODE_GMII:
515 case CVMX_HELPER_INTERFACE_MODE_SPI:
516 case CVMX_HELPER_INTERFACE_MODE_SGMII:
517 case CVMX_HELPER_INTERFACE_MODE_PICMG:
518 cvmx_gmx_set_backpressure_override(interface, 0xf);
519 break;
520 }
521 }
522#endif
523
524 return 0;
525}
526
527/**
528 * Enable packet input/output from the hardware. This function is
529 * called after all internal setup is complete and IPD is enabled.
530 * After this function completes, packets will be accepted from the
531 * hardware ports. PKO should still be disabled to make sure packets
532 * aren't sent out partially setup hardware.
533 *
534 * @interface: Interface to enable
535 *
536 * Returns Zero on success, negative on failure
537 */
538static int __cvmx_helper_packet_hardware_enable(int interface)
539{
540 int result = 0;
541 switch (cvmx_helper_interface_get_mode(interface)) {
542 /* These types don't support ports to IPD/PKO */
543 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
544 case CVMX_HELPER_INTERFACE_MODE_PCIE:
545 /* Nothing to do */
546 break;
547 /* XAUI is a single high speed port */
548 case CVMX_HELPER_INTERFACE_MODE_XAUI:
549 result = __cvmx_helper_xaui_enable(interface);
550 break;
551 /*
552 * RGMII/GMII/MII are all treated about the same. Most
553 * functions refer to these ports as RGMII
554 */
555 case CVMX_HELPER_INTERFACE_MODE_RGMII:
556 case CVMX_HELPER_INTERFACE_MODE_GMII:
557 result = __cvmx_helper_rgmii_enable(interface);
558 break;
559 /*
560 * SPI4 can have 1-16 ports depending on the device at
561 * the other end
562 */
563 case CVMX_HELPER_INTERFACE_MODE_SPI:
564 result = __cvmx_helper_spi_enable(interface);
565 break;
566 /*
567 * SGMII can have 1-4 ports depending on how many are
568 * hooked up
569 */
570 case CVMX_HELPER_INTERFACE_MODE_SGMII:
571 case CVMX_HELPER_INTERFACE_MODE_PICMG:
572 result = __cvmx_helper_sgmii_enable(interface);
573 break;
574 /* PCI target Network Packet Interface */
575 case CVMX_HELPER_INTERFACE_MODE_NPI:
576 result = __cvmx_helper_npi_enable(interface);
577 break;
578 /*
579 * Special loopback only ports. These are not the same
580 * as other ports in loopback mode
581 */
582 case CVMX_HELPER_INTERFACE_MODE_LOOP:
583 result = __cvmx_helper_loop_enable(interface);
584 break;
585 }
586 result |= __cvmx_helper_board_hardware_enable(interface);
587 return result;
588}
589
590/**
591 * Function to adjust internal IPD pointer alignments
592 *
593 * Returns 0 on success
594 * !0 on failure
595 */
596int __cvmx_helper_errata_fix_ipd_ptr_alignment(void)
597{
598#define FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES \
599 (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_FIRST_MBUFF_SKIP)
600#define FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES \
601 (CVMX_FPA_PACKET_POOL_SIZE-8-CVMX_HELPER_NOT_FIRST_MBUFF_SKIP)
602#define FIX_IPD_OUTPORT 0
603 /* Ports 0-15 are interface 0, 16-31 are interface 1 */
604#define INTERFACE(port) (port >> 4)
605#define INDEX(port) (port & 0xf)
606 uint64_t *p64;
607 cvmx_pko_command_word0_t pko_command;
608 union cvmx_buf_ptr g_buffer, pkt_buffer;
609 cvmx_wqe_t *work;
610 int size, num_segs = 0, wqe_pcnt, pkt_pcnt;
611 union cvmx_gmxx_prtx_cfg gmx_cfg;
612 int retry_cnt;
613 int retry_loop_cnt;
614 int i;
615 cvmx_helper_link_info_t link_info;
616
617 /* Save values for restore at end */
618 uint64_t prtx_cfg =
619 cvmx_read_csr(CVMX_GMXX_PRTX_CFG
620 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
621 uint64_t tx_ptr_en =
622 cvmx_read_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
623 uint64_t rx_ptr_en =
624 cvmx_read_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)));
625 uint64_t rxx_jabber =
626 cvmx_read_csr(CVMX_GMXX_RXX_JABBER
627 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
628 uint64_t frame_max =
629 cvmx_read_csr(CVMX_GMXX_RXX_FRM_MAX
630 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)));
631
632 /* Configure port to gig FDX as required for loopback mode */
633 cvmx_helper_rgmii_internal_loopback(FIX_IPD_OUTPORT);
634
635 /*
636 * Disable reception on all ports so if traffic is present it
637 * will not interfere.
638 */
639 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)), 0);
640
641 cvmx_wait(100000000ull);
642
643 for (retry_loop_cnt = 0; retry_loop_cnt < 10; retry_loop_cnt++) {
644 retry_cnt = 100000;
645 wqe_pcnt = cvmx_read_csr(CVMX_IPD_PTR_COUNT);
646 pkt_pcnt = (wqe_pcnt >> 7) & 0x7f;
647 wqe_pcnt &= 0x7f;
648
649 num_segs = (2 + pkt_pcnt - wqe_pcnt) & 3;
650
651 if (num_segs == 0)
652 goto fix_ipd_exit;
653
654 num_segs += 1;
655
656 size =
657 FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES +
658 ((num_segs - 1) * FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES) -
659 (FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES / 2);
660
661 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)),
662 1 << INDEX(FIX_IPD_OUTPORT));
663 CVMX_SYNC;
664
665 g_buffer.u64 = 0;
666 g_buffer.s.addr =
667 cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_WQE_POOL));
668 if (g_buffer.s.addr == 0) {
669 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
670 "buffer allocation failure.\n");
671 goto fix_ipd_exit;
672 }
673
674 g_buffer.s.pool = CVMX_FPA_WQE_POOL;
675 g_buffer.s.size = num_segs;
676
677 pkt_buffer.u64 = 0;
678 pkt_buffer.s.addr =
679 cvmx_ptr_to_phys(cvmx_fpa_alloc(CVMX_FPA_PACKET_POOL));
680 if (pkt_buffer.s.addr == 0) {
681 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
682 "buffer allocation failure.\n");
683 goto fix_ipd_exit;
684 }
685 pkt_buffer.s.i = 1;
686 pkt_buffer.s.pool = CVMX_FPA_PACKET_POOL;
687 pkt_buffer.s.size = FIX_IPD_FIRST_BUFF_PAYLOAD_BYTES;
688
689 p64 = (uint64_t *) cvmx_phys_to_ptr(pkt_buffer.s.addr);
690 p64[0] = 0xffffffffffff0000ull;
691 p64[1] = 0x08004510ull;
692 p64[2] = ((uint64_t) (size - 14) << 48) | 0x5ae740004000ull;
693 p64[3] = 0x3a5fc0a81073c0a8ull;
694
695 for (i = 0; i < num_segs; i++) {
696 if (i > 0)
697 pkt_buffer.s.size =
698 FIX_IPD_NON_FIRST_BUFF_PAYLOAD_BYTES;
699
700 if (i == (num_segs - 1))
701 pkt_buffer.s.i = 0;
702
703 *(uint64_t *) cvmx_phys_to_ptr(g_buffer.s.addr +
704 8 * i) = pkt_buffer.u64;
705 }
706
707 /* Build the PKO command */
708 pko_command.u64 = 0;
709 pko_command.s.segs = num_segs;
710 pko_command.s.total_bytes = size;
711 pko_command.s.dontfree = 0;
712 pko_command.s.gather = 1;
713
714 gmx_cfg.u64 =
715 cvmx_read_csr(CVMX_GMXX_PRTX_CFG
716 (INDEX(FIX_IPD_OUTPORT),
717 INTERFACE(FIX_IPD_OUTPORT)));
718 gmx_cfg.s.en = 1;
719 cvmx_write_csr(CVMX_GMXX_PRTX_CFG
720 (INDEX(FIX_IPD_OUTPORT),
721 INTERFACE(FIX_IPD_OUTPORT)), gmx_cfg.u64);
722 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
723 1 << INDEX(FIX_IPD_OUTPORT));
724 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
725 1 << INDEX(FIX_IPD_OUTPORT));
726
727 cvmx_write_csr(CVMX_GMXX_RXX_JABBER
728 (INDEX(FIX_IPD_OUTPORT),
729 INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
730 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
731 (INDEX(FIX_IPD_OUTPORT),
732 INTERFACE(FIX_IPD_OUTPORT)), 65392 - 14 - 4);
733
734 cvmx_pko_send_packet_prepare(FIX_IPD_OUTPORT,
735 cvmx_pko_get_base_queue
736 (FIX_IPD_OUTPORT),
737 CVMX_PKO_LOCK_CMD_QUEUE);
738 cvmx_pko_send_packet_finish(FIX_IPD_OUTPORT,
739 cvmx_pko_get_base_queue
740 (FIX_IPD_OUTPORT), pko_command,
741 g_buffer, CVMX_PKO_LOCK_CMD_QUEUE);
742
743 CVMX_SYNC;
744
745 do {
746 work = cvmx_pow_work_request_sync(CVMX_POW_WAIT);
747 retry_cnt--;
748 } while ((work == NULL) && (retry_cnt > 0));
749
750 if (!retry_cnt)
751 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT "
752 "get_work() timeout occurred.\n");
753
754 /* Free packet */
755 if (work)
756 cvmx_helper_free_packet_data(work);
757 }
758
759fix_ipd_exit:
760
761 /* Return CSR configs to saved values */
762 cvmx_write_csr(CVMX_GMXX_PRTX_CFG
763 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
764 prtx_cfg);
765 cvmx_write_csr(CVMX_ASXX_TX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
766 tx_ptr_en);
767 cvmx_write_csr(CVMX_ASXX_RX_PRT_EN(INTERFACE(FIX_IPD_OUTPORT)),
768 rx_ptr_en);
769 cvmx_write_csr(CVMX_GMXX_RXX_JABBER
770 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
771 rxx_jabber);
772 cvmx_write_csr(CVMX_GMXX_RXX_FRM_MAX
773 (INDEX(FIX_IPD_OUTPORT), INTERFACE(FIX_IPD_OUTPORT)),
774 frame_max);
775 cvmx_write_csr(CVMX_ASXX_PRT_LOOP(INTERFACE(FIX_IPD_OUTPORT)), 0);
776 /* Set link to down so autonegotiation will set it up again */
777 link_info.u64 = 0;
778 cvmx_helper_link_set(FIX_IPD_OUTPORT, link_info);
779
780 /*
781 * Bring the link back up as autonegotiation is not done in
782 * user applications.
783 */
784 cvmx_helper_link_autoconf(FIX_IPD_OUTPORT);
785
786 CVMX_SYNC;
787 if (num_segs)
788 cvmx_dprintf("WARNING: FIX_IPD_PTR_ALIGNMENT failed.\n");
789
790 return !!num_segs;
791
792}
793
794/**
795 * Called after all internal packet IO paths are setup. This
796 * function enables IPD/PIP and begins packet input and output.
797 *
798 * Returns Zero on success, negative on failure
799 */
800int cvmx_helper_ipd_and_packet_input_enable(void)
801{
802 int num_interfaces;
803 int interface;
804
805 /* Enable IPD */
806 cvmx_ipd_enable();
807
808 /*
809 * Time to enable hardware ports packet input and output. Note
810 * that at this point IPD/PIP must be fully functional and PKO
811 * must be disabled
812 */
813 num_interfaces = cvmx_helper_get_number_of_interfaces();
814 for (interface = 0; interface < num_interfaces; interface++) {
815 if (cvmx_helper_ports_on_interface(interface) > 0)
816 __cvmx_helper_packet_hardware_enable(interface);
817 }
818
819 /* Finally enable PKO now that the entire path is up and running */
820 cvmx_pko_enable();
821
822 if ((OCTEON_IS_MODEL(OCTEON_CN31XX_PASS1)
823 || OCTEON_IS_MODEL(OCTEON_CN30XX_PASS1))
824 && (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM))
825 __cvmx_helper_errata_fix_ipd_ptr_alignment();
826 return 0;
827}
828
829/**
830 * Initialize the PIP, IPD, and PKO hardware to support
831 * simple priority based queues for the ethernet ports. Each
832 * port is configured with a number of priority queues based
833 * on CVMX_PKO_QUEUES_PER_PORT_* where each queue is lower
834 * priority than the previous.
835 *
836 * Returns Zero on success, non-zero on failure
837 */
838int cvmx_helper_initialize_packet_io_global(void)
839{
840 int result = 0;
841 int interface;
842 union cvmx_l2c_cfg l2c_cfg;
843 union cvmx_smix_en smix_en;
844 const int num_interfaces = cvmx_helper_get_number_of_interfaces();
845
846 /*
847 * CN52XX pass 1: Due to a bug in 2nd order CDR, it needs to
848 * be disabled.
849 */
850 if (OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_0))
851 __cvmx_helper_errata_qlm_disable_2nd_order_cdr(1);
852
853 /*
854 * Tell L2 to give the IOB statically higher priority compared
855 * to the cores. This avoids conditions where IO blocks might
856 * be starved under very high L2 loads.
857 */
858 l2c_cfg.u64 = cvmx_read_csr(CVMX_L2C_CFG);
859 l2c_cfg.s.lrf_arb_mode = 0;
860 l2c_cfg.s.rfb_arb_mode = 0;
861 cvmx_write_csr(CVMX_L2C_CFG, l2c_cfg.u64);
862
863 /* Make sure SMI/MDIO is enabled so we can query PHYs */
864 smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(0));
865 if (!smix_en.s.en) {
866 smix_en.s.en = 1;
867 cvmx_write_csr(CVMX_SMIX_EN(0), smix_en.u64);
868 }
869
870 /* Newer chips actually have two SMI/MDIO interfaces */
871 if (!OCTEON_IS_MODEL(OCTEON_CN3XXX) &&
872 !OCTEON_IS_MODEL(OCTEON_CN58XX) &&
873 !OCTEON_IS_MODEL(OCTEON_CN50XX)) {
874 smix_en.u64 = cvmx_read_csr(CVMX_SMIX_EN(1));
875 if (!smix_en.s.en) {
876 smix_en.s.en = 1;
877 cvmx_write_csr(CVMX_SMIX_EN(1), smix_en.u64);
878 }
879 }
880
881 cvmx_pko_initialize_global();
882 for (interface = 0; interface < num_interfaces; interface++) {
883 result |= cvmx_helper_interface_probe(interface);
884 if (cvmx_helper_ports_on_interface(interface) > 0)
885 cvmx_dprintf("Interface %d has %d ports (%s)\n",
886 interface,
887 cvmx_helper_ports_on_interface(interface),
888 cvmx_helper_interface_mode_to_string
889 (cvmx_helper_interface_get_mode
890 (interface)));
891 result |= __cvmx_helper_interface_setup_ipd(interface);
892 result |= __cvmx_helper_interface_setup_pko(interface);
893 }
894
895 result |= __cvmx_helper_global_setup_ipd();
896 result |= __cvmx_helper_global_setup_pko();
897
898 /* Enable any flow control and backpressure */
899 result |= __cvmx_helper_global_setup_backpressure();
900
901#if CVMX_HELPER_ENABLE_IPD
902 result |= cvmx_helper_ipd_and_packet_input_enable();
903#endif
904 return result;
905}
906
907/**
908 * Does core local initialization for packet io
909 *
910 * Returns Zero on success, non-zero on failure
911 */
912int cvmx_helper_initialize_packet_io_local(void)
913{
914 return cvmx_pko_initialize_local();
915}
916
917/**
918 * Auto configure an IPD/PKO port link state and speed. This
919 * function basically does the equivalent of:
920 * cvmx_helper_link_set(ipd_port, cvmx_helper_link_get(ipd_port));
921 *
922 * @ipd_port: IPD/PKO port to auto configure
923 *
924 * Returns Link state after configure
925 */
926cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
927{
928 cvmx_helper_link_info_t link_info;
929 int interface = cvmx_helper_get_interface_num(ipd_port);
930 int index = cvmx_helper_get_interface_index_num(ipd_port);
931
932 if (index >= cvmx_helper_ports_on_interface(interface)) {
933 link_info.u64 = 0;
934 return link_info;
935 }
936
937 link_info = cvmx_helper_link_get(ipd_port);
938 if (link_info.u64 == port_link_info[ipd_port].u64)
939 return link_info;
940
941 /* If we fail to set the link speed, port_link_info will not change */
942 cvmx_helper_link_set(ipd_port, link_info);
943
944 /*
945 * port_link_info should be the current value, which will be
946 * different than expect if cvmx_helper_link_set() failed.
947 */
948 return port_link_info[ipd_port];
949}
950
951/**
952 * Return the link state of an IPD/PKO port as returned by
953 * auto negotiation. The result of this function may not match
954 * Octeon's link config if auto negotiation has changed since
955 * the last call to cvmx_helper_link_set().
956 *
957 * @ipd_port: IPD/PKO port to query
958 *
959 * Returns Link state
960 */
961cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
962{
963 cvmx_helper_link_info_t result;
964 int interface = cvmx_helper_get_interface_num(ipd_port);
965 int index = cvmx_helper_get_interface_index_num(ipd_port);
966
967 /* The default result will be a down link unless the code below
968 changes it */
969 result.u64 = 0;
970
971 if (index >= cvmx_helper_ports_on_interface(interface))
972 return result;
973
974 switch (cvmx_helper_interface_get_mode(interface)) {
975 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
976 case CVMX_HELPER_INTERFACE_MODE_PCIE:
977 /* Network links are not supported */
978 break;
979 case CVMX_HELPER_INTERFACE_MODE_XAUI:
980 result = __cvmx_helper_xaui_link_get(ipd_port);
981 break;
982 case CVMX_HELPER_INTERFACE_MODE_GMII:
983 if (index == 0)
984 result = __cvmx_helper_rgmii_link_get(ipd_port);
985 else {
986 result.s.full_duplex = 1;
987 result.s.link_up = 1;
988 result.s.speed = 1000;
989 }
990 break;
991 case CVMX_HELPER_INTERFACE_MODE_RGMII:
992 result = __cvmx_helper_rgmii_link_get(ipd_port);
993 break;
994 case CVMX_HELPER_INTERFACE_MODE_SPI:
995 result = __cvmx_helper_spi_link_get(ipd_port);
996 break;
997 case CVMX_HELPER_INTERFACE_MODE_SGMII:
998 case CVMX_HELPER_INTERFACE_MODE_PICMG:
999 result = __cvmx_helper_sgmii_link_get(ipd_port);
1000 break;
1001 case CVMX_HELPER_INTERFACE_MODE_NPI:
1002 case CVMX_HELPER_INTERFACE_MODE_LOOP:
1003 /* Network links are not supported */
1004 break;
1005 }
1006 return result;
1007}
1008
1009/**
1010 * Configure an IPD/PKO port for the specified link state. This
1011 * function does not influence auto negotiation at the PHY level.
1012 * The passed link state must always match the link state returned
1013 * by cvmx_helper_link_get(). It is normally best to use
1014 * cvmx_helper_link_autoconf() instead.
1015 *
1016 * @ipd_port: IPD/PKO port to configure
1017 * @link_info: The new link state
1018 *
1019 * Returns Zero on success, negative on failure
1020 */
1021int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
1022{
1023 int result = -1;
1024 int interface = cvmx_helper_get_interface_num(ipd_port);
1025 int index = cvmx_helper_get_interface_index_num(ipd_port);
1026
1027 if (index >= cvmx_helper_ports_on_interface(interface))
1028 return -1;
1029
1030 switch (cvmx_helper_interface_get_mode(interface)) {
1031 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1032 case CVMX_HELPER_INTERFACE_MODE_PCIE:
1033 break;
1034 case CVMX_HELPER_INTERFACE_MODE_XAUI:
1035 result = __cvmx_helper_xaui_link_set(ipd_port, link_info);
1036 break;
1037 /*
1038 * RGMII/GMII/MII are all treated about the same. Most
1039 * functions refer to these ports as RGMII.
1040 */
1041 case CVMX_HELPER_INTERFACE_MODE_RGMII:
1042 case CVMX_HELPER_INTERFACE_MODE_GMII:
1043 result = __cvmx_helper_rgmii_link_set(ipd_port, link_info);
1044 break;
1045 case CVMX_HELPER_INTERFACE_MODE_SPI:
1046 result = __cvmx_helper_spi_link_set(ipd_port, link_info);
1047 break;
1048 case CVMX_HELPER_INTERFACE_MODE_SGMII:
1049 case CVMX_HELPER_INTERFACE_MODE_PICMG:
1050 result = __cvmx_helper_sgmii_link_set(ipd_port, link_info);
1051 break;
1052 case CVMX_HELPER_INTERFACE_MODE_NPI:
1053 case CVMX_HELPER_INTERFACE_MODE_LOOP:
1054 break;
1055 }
1056 /* Set the port_link_info here so that the link status is updated
1057 no matter how cvmx_helper_link_set is called. We don't change
1058 the value if link_set failed */
1059 if (result == 0)
1060 port_link_info[ipd_port].u64 = link_info.u64;
1061 return result;
1062}
1063
1064/**
1065 * Configure a port for internal and/or external loopback. Internal loopback
1066 * causes packets sent by the port to be received by Octeon. External loopback
1067 * causes packets received from the wire to sent out again.
1068 *
1069 * @ipd_port: IPD/PKO port to loopback.
1070 * @enable_internal:
1071 * Non zero if you want internal loopback
1072 * @enable_external:
1073 * Non zero if you want external loopback
1074 *
1075 * Returns Zero on success, negative on failure.
1076 */
1077int cvmx_helper_configure_loopback(int ipd_port, int enable_internal,
1078 int enable_external)
1079{
1080 int result = -1;
1081 int interface = cvmx_helper_get_interface_num(ipd_port);
1082 int index = cvmx_helper_get_interface_index_num(ipd_port);
1083
1084 if (index >= cvmx_helper_ports_on_interface(interface))
1085 return -1;
1086
1087 switch (cvmx_helper_interface_get_mode(interface)) {
1088 case CVMX_HELPER_INTERFACE_MODE_DISABLED:
1089 case CVMX_HELPER_INTERFACE_MODE_PCIE:
1090 case CVMX_HELPER_INTERFACE_MODE_SPI:
1091 case CVMX_HELPER_INTERFACE_MODE_NPI:
1092 case CVMX_HELPER_INTERFACE_MODE_LOOP:
1093 break;
1094 case CVMX_HELPER_INTERFACE_MODE_XAUI:
1095 result =
1096 __cvmx_helper_xaui_configure_loopback(ipd_port,
1097 enable_internal,
1098 enable_external);
1099 break;
1100 case CVMX_HELPER_INTERFACE_MODE_RGMII:
1101 case CVMX_HELPER_INTERFACE_MODE_GMII:
1102 result =
1103 __cvmx_helper_rgmii_configure_loopback(ipd_port,
1104 enable_internal,
1105 enable_external);
1106 break;
1107 case CVMX_HELPER_INTERFACE_MODE_SGMII:
1108 case CVMX_HELPER_INTERFACE_MODE_PICMG:
1109 result =
1110 __cvmx_helper_sgmii_configure_loopback(ipd_port,
1111 enable_internal,
1112 enable_external);
1113 break;
1114 }
1115 return result;
1116}
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 00000000000..e59d1b79f24
--- /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 00000000000..bea7538ea4e
--- /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 00000000000..f557084b109
--- /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 00000000000..74afb1710cd
--- /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}
diff --git a/arch/mips/cavium-octeon/executive/octeon-model.c b/arch/mips/cavium-octeon/executive/octeon-model.c
index c8d35684504..f4c1b36fdf6 100644
--- a/arch/mips/cavium-octeon/executive/octeon-model.c
+++ b/arch/mips/cavium-octeon/executive/octeon-model.c
@@ -4,7 +4,7 @@
4 * Contact: support@caviumnetworks.com 4 * Contact: support@caviumnetworks.com
5 * This file is part of the OCTEON SDK 5 * This file is part of the OCTEON SDK
6 * 6 *
7 * Copyright (c) 2003-2008 Cavium Networks 7 * Copyright (c) 2003-2010 Cavium Networks
8 * 8 *
9 * This file is free software; you can redistribute it and/or modify 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 10 * it under the terms of the GNU General Public License, Version 2, as
@@ -25,10 +25,6 @@
25 * Contact Cavium Networks for more information 25 * Contact Cavium Networks for more information
26 ***********************license end**************************************/ 26 ***********************license end**************************************/
27 27
28/*
29 * File defining functions for working with different Octeon
30 * models.
31 */
32#include <asm/octeon/octeon.h> 28#include <asm/octeon/octeon.h>
33 29
34/** 30/**
@@ -69,11 +65,12 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
69 char fuse_model[10]; 65 char fuse_model[10];
70 uint32_t fuse_data = 0; 66 uint32_t fuse_data = 0;
71 67
72 fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3); 68 fus3.u64 = 0;
69 if (!OCTEON_IS_MODEL(OCTEON_CN6XXX))
70 fus3.u64 = cvmx_read_csr(CVMX_L2D_FUS3);
73 fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2); 71 fus_dat2.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT2);
74 fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3); 72 fus_dat3.u64 = cvmx_read_csr(CVMX_MIO_FUS_DAT3);
75 73 num_cores = cvmx_pop(cvmx_read_csr(CVMX_CIU_FUSE));
76 num_cores = cvmx_octeon_num_cores();
77 74
78 /* Make sure the non existent devices look disabled */ 75 /* Make sure the non existent devices look disabled */
79 switch ((chip_id >> 8) & 0xff) { 76 switch ((chip_id >> 8) & 0xff) {
@@ -108,7 +105,7 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
108 * Assume pass number is encoded using <5:3><2:0>. Exceptions 105 * Assume pass number is encoded using <5:3><2:0>. Exceptions
109 * will be fixed later. 106 * will be fixed later.
110 */ 107 */
111 sprintf(pass, "%u.%u", ((chip_id >> 3) & 7) + 1, chip_id & 7); 108 sprintf(pass, "%d.%d", (int)((chip_id >> 3) & 7) + 1, (int)chip_id & 7);
112 109
113 /* 110 /*
114 * Use the number of cores to determine the last 2 digits of 111 * Use the number of cores to determine the last 2 digits of
@@ -116,6 +113,12 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
116 * later. 113 * later.
117 */ 114 */
118 switch (num_cores) { 115 switch (num_cores) {
116 case 32:
117 core_model = "80";
118 break;
119 case 24:
120 core_model = "70";
121 break;
119 case 16: 122 case 16:
120 core_model = "60"; 123 core_model = "60";
121 break; 124 break;
@@ -246,8 +249,8 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
246 break; 249 break;
247 case 3: /* CN58XX */ 250 case 3: /* CN58XX */
248 family = "58"; 251 family = "58";
249 /* Special case. 4 core, no crypto */ 252 /* Special case. 4 core, half cache (CP with half cache) */
250 if ((num_cores == 4) && fus_dat2.cn38xx.nocrypto) 253 if ((num_cores == 4) && fus3.cn58xx.crip_1024k && !strncmp(suffix, "CP", 2))
251 core_model = "29"; 254 core_model = "29";
252 255
253 /* Pass 1 uses different encodings for pass numbers */ 256 /* Pass 1 uses different encodings for pass numbers */
@@ -285,6 +288,9 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
285 suffix = "NSP"; 288 suffix = "NSP";
286 if (fus_dat3.s.nozip) 289 if (fus_dat3.s.nozip)
287 suffix = "SCP"; 290 suffix = "SCP";
291
292 if (fus_dat3.s.bar2_en)
293 suffix = "NSPB2";
288 } 294 }
289 if (fus3.cn56xx.crip_1024k) 295 if (fus3.cn56xx.crip_1024k)
290 family = "54"; 296 family = "54";
@@ -301,6 +307,60 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
301 else 307 else
302 family = "52"; 308 family = "52";
303 break; 309 break;
310 case 0x93: /* CN61XX */
311 family = "61";
312 if (fus_dat2.cn61xx.nocrypto && fus_dat2.cn61xx.dorm_crypto)
313 suffix = "AP";
314 if (fus_dat2.cn61xx.nocrypto)
315 suffix = "CP";
316 else if (fus_dat2.cn61xx.dorm_crypto)
317 suffix = "DAP";
318 else if (fus_dat3.cn61xx.nozip)
319 suffix = "SCP";
320 break;
321 case 0x90: /* CN63XX */
322 family = "63";
323 if (fus_dat3.s.l2c_crip == 2)
324 family = "62";
325 if (num_cores == 6) /* Other core counts match generic */
326 core_model = "35";
327 if (fus_dat2.cn63xx.nocrypto)
328 suffix = "CP";
329 else if (fus_dat2.cn63xx.dorm_crypto)
330 suffix = "DAP";
331 else if (fus_dat3.cn63xx.nozip)
332 suffix = "SCP";
333 else
334 suffix = "AAP";
335 break;
336 case 0x92: /* CN66XX */
337 family = "66";
338 if (num_cores == 6) /* Other core counts match generic */
339 core_model = "35";
340 if (fus_dat2.cn66xx.nocrypto && fus_dat2.cn66xx.dorm_crypto)
341 suffix = "AP";
342 if (fus_dat2.cn66xx.nocrypto)
343 suffix = "CP";
344 else if (fus_dat2.cn66xx.dorm_crypto)
345 suffix = "DAP";
346 else if (fus_dat3.cn66xx.nozip)
347 suffix = "SCP";
348 else
349 suffix = "AAP";
350 break;
351 case 0x91: /* CN68XX */
352 family = "68";
353 if (fus_dat2.cn68xx.nocrypto && fus_dat3.cn68xx.nozip)
354 suffix = "CP";
355 else if (fus_dat2.cn68xx.dorm_crypto)
356 suffix = "DAP";
357 else if (fus_dat3.cn68xx.nozip)
358 suffix = "SCP";
359 else if (fus_dat2.cn68xx.nocrypto)
360 suffix = "SP";
361 else
362 suffix = "AAP";
363 break;
304 default: 364 default:
305 family = "XX"; 365 family = "XX";
306 core_model = "XX"; 366 core_model = "XX";
@@ -310,49 +370,40 @@ const char *octeon_model_get_string_buffer(uint32_t chip_id, char *buffer)
310 } 370 }
311 371
312 clock_mhz = octeon_get_clock_rate() / 1000000; 372 clock_mhz = octeon_get_clock_rate() / 1000000;
313
314 if (family[0] != '3') { 373 if (family[0] != '3') {
374 int fuse_base = 384 / 8;
375 if (family[0] == '6')
376 fuse_base = 832 / 8;
377
315 /* Check for model in fuses, overrides normal decode */ 378 /* Check for model in fuses, overrides normal decode */
316 /* This is _not_ valid for Octeon CN3XXX models */ 379 /* This is _not_ valid for Octeon CN3XXX models */
317 fuse_data |= cvmx_fuse_read_byte(51); 380 fuse_data |= cvmx_fuse_read_byte(fuse_base + 3);
318 fuse_data = fuse_data << 8; 381 fuse_data = fuse_data << 8;
319 fuse_data |= cvmx_fuse_read_byte(50); 382 fuse_data |= cvmx_fuse_read_byte(fuse_base + 2);
320 fuse_data = fuse_data << 8; 383 fuse_data = fuse_data << 8;
321 fuse_data |= cvmx_fuse_read_byte(49); 384 fuse_data |= cvmx_fuse_read_byte(fuse_base + 1);
322 fuse_data = fuse_data << 8; 385 fuse_data = fuse_data << 8;
323 fuse_data |= cvmx_fuse_read_byte(48); 386 fuse_data |= cvmx_fuse_read_byte(fuse_base);
324 if (fuse_data & 0x7ffff) { 387 if (fuse_data & 0x7ffff) {
325 int model = fuse_data & 0x3fff; 388 int model = fuse_data & 0x3fff;
326 int suffix = (fuse_data >> 14) & 0x1f; 389 int suffix = (fuse_data >> 14) & 0x1f;
327 if (suffix && model) { 390 if (suffix && model) {
328 /* 391 /* Have both number and suffix in fuses, so both */
329 * Have both number and suffix in 392 sprintf(fuse_model, "%d%c", model, 'A' + suffix - 1);
330 * fuses, so both
331 */
332 sprintf(fuse_model, "%d%c",
333 model, 'A' + suffix - 1);
334 core_model = ""; 393 core_model = "";
335 family = fuse_model; 394 family = fuse_model;
336 } else if (suffix && !model) { 395 } else if (suffix && !model) {
337 /* 396 /* Only have suffix, so add suffix to 'normal' model number */
338 * Only have suffix, so add suffix to 397 sprintf(fuse_model, "%s%c", core_model, 'A' + suffix - 1);
339 * 'normal' model number.
340 */
341 sprintf(fuse_model, "%s%c", core_model,
342 'A' + suffix - 1);
343 core_model = fuse_model; 398 core_model = fuse_model;
344 } else { 399 } else {
345 /* 400 /* Don't have suffix, so just use model from fuses */
346 * Don't have suffix, so just use
347 * model from fuses.
348 */
349 sprintf(fuse_model, "%d", model); 401 sprintf(fuse_model, "%d", model);
350 core_model = ""; 402 core_model = "";
351 family = fuse_model; 403 family = fuse_model;
352 } 404 }
353 } 405 }
354 } 406 }
355 sprintf(buffer, "CN%s%sp%s-%d-%s", 407 sprintf(buffer, "CN%s%sp%s-%d-%s", family, core_model, pass, clock_mhz, suffix);
356 family, core_model, pass, clock_mhz, suffix);
357 return buffer; 408 return buffer;
358} 409}