1 // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2 /* Copyright (C) 2015-2018 Netronome Systems, Inc. */
6 * Library of functions to access the NFP's CPP bus
7 * Authors: Jakub Kicinski <jakub.kicinski@netronome.com>
8 * Jason McMullan <jason.mcmullan@netronome.com>
9 * Rolf Neugebauer <rolf.neugebauer@netronome.com>
12 #include <asm/unaligned.h>
13 #include <linux/bitfield.h>
14 #include <linux/delay.h>
15 #include <linux/kernel.h>
16 #include <linux/module.h>
17 #include <linux/slab.h>
18 #include <linux/sched.h>
21 #include "nfp6000/nfp6000.h"
22 #include "nfp6000/nfp_xpb.h"
25 #define NFP_PL_DEVICE_ID 0x00000004
26 #define NFP_PL_DEVICE_ID_MASK GENMASK(7, 0)
28 #define NFP6000_ARM_GCSR_SOFTMODEL0 0x00400144
31 * nfp_cpp_readl() - Read a u32 word from a CPP location
32 * @cpp: CPP device handle
33 * @cpp_id: CPP ID for operation
34 * @address: Address for operation
35 * @value: Pointer to read buffer
37 * Return: 0 on success, or -ERRNO
39 int nfp_cpp_readl(struct nfp_cpp *cpp, u32 cpp_id,
40 unsigned long long address, u32 *value)
45 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
47 return n < 0 ? n : -EIO;
49 *value = get_unaligned_le32(tmp);
54 * nfp_cpp_writel() - Write a u32 word to a CPP location
55 * @cpp: CPP device handle
56 * @cpp_id: CPP ID for operation
57 * @address: Address for operation
58 * @value: Value to write
60 * Return: 0 on success, or -ERRNO
62 int nfp_cpp_writel(struct nfp_cpp *cpp, u32 cpp_id,
63 unsigned long long address, u32 value)
68 put_unaligned_le32(value, tmp);
69 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
71 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
75 * nfp_cpp_readq() - Read a u64 word from a CPP location
76 * @cpp: CPP device handle
77 * @cpp_id: CPP ID for operation
78 * @address: Address for operation
79 * @value: Pointer to read buffer
81 * Return: 0 on success, or -ERRNO
83 int nfp_cpp_readq(struct nfp_cpp *cpp, u32 cpp_id,
84 unsigned long long address, u64 *value)
89 n = nfp_cpp_read(cpp, cpp_id, address, tmp, sizeof(tmp));
91 return n < 0 ? n : -EIO;
93 *value = get_unaligned_le64(tmp);
98 * nfp_cpp_writeq() - Write a u64 word to a CPP location
99 * @cpp: CPP device handle
100 * @cpp_id: CPP ID for operation
101 * @address: Address for operation
102 * @value: Value to write
104 * Return: 0 on success, or -ERRNO
106 int nfp_cpp_writeq(struct nfp_cpp *cpp, u32 cpp_id,
107 unsigned long long address, u64 value)
112 put_unaligned_le64(value, tmp);
113 n = nfp_cpp_write(cpp, cpp_id, address, tmp, sizeof(tmp));
115 return n == sizeof(tmp) ? 0 : n < 0 ? n : -EIO;
118 /* NOTE: This code should not use nfp_xpb_* functions,
119 * as those are model-specific
121 int nfp_cpp_model_autodetect(struct nfp_cpp *cpp, u32 *model)
123 const u32 arm_id = NFP_CPP_ID(NFP_CPP_TARGET_ARM, 0, 0);
127 err = nfp_cpp_readl(cpp, arm_id, NFP6000_ARM_GCSR_SOFTMODEL0, model);
131 /* The PL's PluDeviceID revision code is authoratative */
133 err = nfp_xpb_readl(cpp, NFP_XPB_DEVICE(1, 1, 16) + NFP_PL_DEVICE_ID,
138 *model |= (NFP_PL_DEVICE_ID_MASK & reg) - 0x10;
143 static u8 nfp_bytemask(int width, u64 addr)
148 return 0x0f << (addr & 4);
150 return 0x03 << (addr & 6);
152 return 0x01 << (addr & 7);
157 int nfp_cpp_explicit_read(struct nfp_cpp *cpp, u32 cpp_id,
158 u64 addr, void *buff, size_t len, int width_read)
160 struct nfp_cpp_explicit *expl;
165 if (len & (width_read - 1))
168 expl = nfp_cpp_explicit_acquire(cpp);
172 incr = min_t(int, 16 * width_read, 128);
173 incr = min_t(int, incr, len);
175 /* Translate a NFP_CPP_ACTION_RW to action 0 */
176 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
177 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 0,
178 NFP_CPP_ID_TOKEN_of(cpp_id));
180 byte_mask = nfp_bytemask(width_read, addr);
182 nfp_cpp_explicit_set_target(expl, cpp_id,
183 incr / width_read - 1, byte_mask);
184 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PUSH,
187 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
188 if (i + incr > len) {
190 nfp_cpp_explicit_set_target(expl, cpp_id,
191 incr / width_read - 1,
195 err = nfp_cpp_explicit_do(expl, addr);
199 err = nfp_cpp_explicit_get(expl, tmp, incr);
205 nfp_cpp_explicit_release(expl);
210 int nfp_cpp_explicit_write(struct nfp_cpp *cpp, u32 cpp_id, u64 addr,
211 const void *buff, size_t len, int width_write)
213 struct nfp_cpp_explicit *expl;
214 const char *tmp = buff;
218 if (len & (width_write - 1))
221 expl = nfp_cpp_explicit_acquire(cpp);
225 incr = min_t(int, 16 * width_write, 128);
226 incr = min_t(int, incr, len);
228 /* Translate a NFP_CPP_ACTION_RW to action 1 */
229 if (NFP_CPP_ID_ACTION_of(cpp_id) == NFP_CPP_ACTION_RW)
230 cpp_id = NFP_CPP_ID(NFP_CPP_ID_TARGET_of(cpp_id), 1,
231 NFP_CPP_ID_TOKEN_of(cpp_id));
233 byte_mask = nfp_bytemask(width_write, addr);
235 nfp_cpp_explicit_set_target(expl, cpp_id,
236 incr / width_write - 1, byte_mask);
237 nfp_cpp_explicit_set_posted(expl, 1, 0, NFP_SIGNAL_PULL,
240 for (i = 0; i < len; i += incr, addr += incr, tmp += incr) {
241 if (i + incr > len) {
243 nfp_cpp_explicit_set_target(expl, cpp_id,
244 incr / width_write - 1,
248 err = nfp_cpp_explicit_put(expl, tmp, incr);
252 err = nfp_cpp_explicit_do(expl, addr);
258 nfp_cpp_explicit_release(expl);
264 * nfp_cpp_map_area() - Helper function to map an area
265 * @cpp: NFP CPP handler
266 * @name: Name for the area
267 * @cpp_id: CPP ID for operation
269 * @size: Size of the area
270 * @area: Area handle (output)
272 * Map an area of IOMEM access. To undo the effect of this function call
273 * @nfp_cpp_area_release_free(*area).
275 * Return: Pointer to memory mapped area or ERR_PTR
278 nfp_cpp_map_area(struct nfp_cpp *cpp, const char *name, u32 cpp_id, u64 addr,
279 unsigned long size, struct nfp_cpp_area **area)
283 *area = nfp_cpp_area_alloc_acquire(cpp, name, cpp_id, addr, size);
287 res = nfp_cpp_area_iomem(*area);
289 goto err_release_free;
294 nfp_cpp_area_release_free(*area);
296 return (u8 __iomem *)ERR_PTR(-EIO);