2 * Copyright (C) 2015-2017 Netronome Systems, Inc.
4 * This software is dual licensed under the GNU General License Version 2,
5 * June 1991 as shown in the file COPYING in the top-level directory of this
6 * source tree or the BSD 2-Clause License provided below. You have the
7 * option to license this software under the complete terms of either license.
9 * The BSD 2-Clause License:
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
15 * 1. Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
19 * 2. Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36 * Library of functions to access the NFP's CPP bus
37 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
38 * Jason McMullan <jason.mcmullan@netronome.com>
39 * Rolf Neugebauer <rolf.neugebauer@netronome.com>
42 #include <asm/unaligned.h>
43 #include <linux/bitfield.h>
44 #include <linux/delay.h>
45 #include <linux/kernel.h>
46 #include <linux/module.h>
47 #include <linux/slab.h>
48 #include <linux/sched.h>
51 #include "nfp6000/nfp6000.h"
52 #include "nfp6000/nfp_xpb.h"
55 #define NFP_PL_DEVICE_ID 0x00000004
56 #define NFP_PL_DEVICE_ID_MASK GENMASK(7, 0)
58 #define NFP6000_ARM_GCSR_SOFTMODEL0 0x00400144
61 * nfp_cpp_readl() - Read a u32 word from a CPP location
62 * @cpp: CPP device handle
63 * @cpp_id: CPP ID for operation
64 * @address: Address for operation
65 * @value: Pointer to read buffer
67 * Return: 0 on success, or -ERRNO
69 int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
70 unsigned long long address, u32 *value)
75 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
77 return n < 0 ? n : -EIO;
79 *value = get_unaligned_le32(tmp);
84 * nfp_cpp_writel() - Write a u32 word to a CPP location
85 * @cpp: CPP device handle
86 * @cpp_id: CPP ID for operation
87 * @address: Address for operation
88 * @value: Value to write
90 * Return: 0 on success, or -ERRNO
92 int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
93 unsigned long long address, u32 value)
98 put_unaligned_le32(value, tmp);
99 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
101 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
105 * nfp_cpp_readq() - Read a u64 word from a CPP location
106 * @cpp: CPP device handle
107 * @cpp_id: CPP ID for operation
108 * @address: Address for operation
109 * @value: Pointer to read buffer
111 * Return: 0 on success, or -ERRNO
113 int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
114 unsigned long long address, u64 *value)
119 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
120 if (n != sizeof(tmp))
121 return n < 0 ? n : -EIO;
123 *value = get_unaligned_le64(tmp);
128 * nfp_cpp_writeq() - Write a u64 word to a CPP location
129 * @cpp: CPP device handle
130 * @cpp_id: CPP ID for operation
131 * @address: Address for operation
132 * @value: Value to write
134 * Return: 0 on success, or -ERRNO
136 int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
137 unsigned long long address, u64 value)
142 put_unaligned_le64(value, tmp);
143 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
145 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
148 /* NOTE: This code should not use nfp_xpb_* functions,
149 * as those are model-specific
151 int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
153 const u32 arm_id = NFP_CPP_ID(NFP_CPP_TARGET_ARM, 0, 0);
157 err = nfp_cpp_readl(cpp, arm_id, NFP6000_ARM_GCSR_SOFTMODEL0, model);
161 /* The PL's PluDeviceID revision code is authoratative */
163 err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
168 *model |= (NFP_PL_DEVICE_ID_MASK & reg) - 0x10;
173 static u8 nfp_bytemask(int width, u64 addr)
178 return 0x0f << (addr & 4);
180 return 0x03 << (addr & 6);
182 return 0x01 << (addr & 7);
187 int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
188 u64 addr, void *buff, size_t len, int width_read)
190 struct nfp_cpp_explicit *expl;
195 if (len & (width_read - 1))
198 expl = nfp_cpp_explicit_acquire(cpp);
202 incr = min_t(int, 16 * width_read, 128);
203 incr = min_t(int, incr, len);
205 /* Translate a NFP_CPP_ACTION_RW to action 0 */
206 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
207 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
208 NFP_CPP_ID_TOKEN_of(cpp_id));
210 byte_mask = nfp_bytemask(width_read, addr);
212 nfp_cpp_explicit_set_target(expl, cpp_id,
213 incr / width_read - 1, byte_mask);
214 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
217 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
218 if (i + incr > len) {
220 nfp_cpp_explicit_set_target(expl, cpp_id,
221 incr / width_read - 1,
225 err = nfp_cpp_explicit_do(expl, addr);
229 err = nfp_cpp_explicit_get(expl, tmp, incr);
235 nfp_cpp_explicit_release(expl);
240 int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
241 const void *buff, size_t len, int width_write)
243 struct nfp_cpp_explicit *expl;
244 const char *tmp = buff;
248 if (len & (width_write - 1))
251 expl = nfp_cpp_explicit_acquire(cpp);
255 incr = min_t(int, 16 * width_write, 128);
256 incr = min_t(int, incr, len);
258 /* Translate a NFP_CPP_ACTION_RW to action 1 */
259 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
260 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
261 NFP_CPP_ID_TOKEN_of(cpp_id));
263 byte_mask = nfp_bytemask(width_write, addr);
265 nfp_cpp_explicit_set_target(expl, cpp_id,
266 incr / width_write - 1, byte_mask);
267 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
270 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
271 if (i + incr > len) {
273 nfp_cpp_explicit_set_target(expl, cpp_id,
274 incr / width_write - 1,
278 err = nfp_cpp_explicit_put(expl, tmp, incr);
282 err = nfp_cpp_explicit_do(expl, addr);
288 nfp_cpp_explicit_release(expl);
294 * nfp_cpp_map_area() - Helper function to map an area
295 * @cpp: NFP CPP handler
296 * @name: Name for the area
297 * @domain: CPP domain
298 * @target: CPP target
300 * @size: Size of the area
301 * @area: Area handle (output)
303 * Map an area of IOMEM access. To undo the effect of this function call
304 * @nfp_cpp_area_release_free(*area).
306 * Return: Pointer to memory mapped area or ERR_PTR
309 nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, int domain, int target,
310 u64 addr, unsigned long size, struct nfp_cpp_area **area)
315 dest = NFP_CPP_ISLAND_ID(target, NFP_CPP_ACTION_RW, 0, domain);
317 *area = nfp_cpp_area_alloc_acquire(cpp, name, dest, addr, size);
321 res = nfp_cpp_area_iomem(*area);
323 goto err_release_free;
328 nfp_cpp_area_release_free(*area);
330 return (u8 __iomem *)ERR_PTR(-EIO);