blob: 097d5a780264c61800003880277572394b172fa3 [file] [log] [blame]
Thomas Gleixner1802d0b2019-05-27 08:55:21 +02001// SPDX-License-Identifier: GPL-2.0-only
Jeremy Kerr0508ad12017-02-01 10:53:41 -06002/*
3 * FSI core driver
4 *
5 * Copyright (C) IBM Corporation 2016
6 *
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10007 * TODO:
8 * - Rework topology
9 * - s/chip_id/chip_loc
10 * - s/cfam/chip (cfam_id -> chip_id etc...)
Jeremy Kerr0508ad12017-02-01 10:53:41 -060011 */
12
Jeremy Kerr2b545cd2017-06-06 16:08:42 -050013#include <linux/crc4.h>
Jeremy Kerr0508ad12017-02-01 10:53:41 -060014#include <linux/device.h>
15#include <linux/fsi.h>
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050016#include <linux/idr.h>
Jeremy Kerr0508ad12017-02-01 10:53:41 -060017#include <linux/module.h>
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +103018#include <linux/of.h>
Rob Herring23ad7ec2023-06-09 12:30:56 -060019#include <linux/of_address.h>
Eddie Jamesc21d3222023-06-12 14:56:46 -050020#include <linux/of_device.h>
Jeremy Kerr2b545cd2017-06-06 16:08:42 -050021#include <linux/slab.h>
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -050022#include <linux/bitops.h>
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +100023#include <linux/cdev.h>
24#include <linux/fs.h>
25#include <linux/uaccess.h>
Jeremy Kerr0508ad12017-02-01 10:53:41 -060026
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050027#include "fsi-master.h"
Eddie Jamesd5d8dfb2023-06-12 14:56:44 -050028#include "fsi-slave.h"
29
30#define CREATE_TRACE_POINTS
31#include <trace/events/fsi.h>
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050032
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -050033#define FSI_SLAVE_CONF_NEXT_MASK GENMASK(31, 31)
34#define FSI_SLAVE_CONF_SLOTS_MASK GENMASK(23, 16)
35#define FSI_SLAVE_CONF_SLOTS_SHIFT 16
36#define FSI_SLAVE_CONF_VERSION_MASK GENMASK(15, 12)
37#define FSI_SLAVE_CONF_VERSION_SHIFT 12
38#define FSI_SLAVE_CONF_TYPE_MASK GENMASK(11, 4)
39#define FSI_SLAVE_CONF_TYPE_SHIFT 4
40#define FSI_SLAVE_CONF_CRC_SHIFT 4
41#define FSI_SLAVE_CONF_CRC_MASK GENMASK(3, 0)
42#define FSI_SLAVE_CONF_DATA_BITS 28
43
Jeremy Kerr4efe37f2017-06-06 16:08:45 -050044#define FSI_PEEK_BASE 0x410
45
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -050046static const int engine_page_size = 0x400;
47
Christopher Bostic2b37c3e2017-06-06 16:08:43 -050048#define FSI_SLAVE_BASE 0x800
49
50/*
51 * FSI slave engine control register offsets
52 */
Jeremy Kerr1fa847d2017-06-06 16:08:52 -050053#define FSI_SMODE 0x0 /* R/W: Mode register */
54#define FSI_SISC 0x8 /* R/W: Interrupt condition */
55#define FSI_SSTAT 0x14 /* R : Slave status */
Eddie James196964a2020-05-20 13:17:07 -050056#define FSI_SLBUS 0x30 /* W : LBUS Ownership */
Jeremy Kerr4af889b2017-06-06 16:08:58 -050057#define FSI_LLMODE 0x100 /* R/W: Link layer mode register */
Christopher Bostic2b37c3e2017-06-06 16:08:43 -050058
59/*
60 * SMODE fields
61 */
62#define FSI_SMODE_WSC 0x80000000 /* Warm start done */
63#define FSI_SMODE_ECRC 0x20000000 /* Hw CRC check */
64#define FSI_SMODE_SID_SHIFT 24 /* ID shift */
65#define FSI_SMODE_SID_MASK 3 /* ID Mask */
66#define FSI_SMODE_ED_SHIFT 20 /* Echo delay shift */
67#define FSI_SMODE_ED_MASK 0xf /* Echo delay mask */
68#define FSI_SMODE_SD_SHIFT 16 /* Send delay shift */
69#define FSI_SMODE_SD_MASK 0xf /* Send delay mask */
70#define FSI_SMODE_LBCRR_SHIFT 8 /* Clk ratio shift */
71#define FSI_SMODE_LBCRR_MASK 0xf /* Clk ratio mask */
72
Jeremy Kerr4af889b2017-06-06 16:08:58 -050073/*
Eddie James196964a2020-05-20 13:17:07 -050074 * SLBUS fields
75 */
76#define FSI_SLBUS_FORCE 0x80000000 /* Force LBUS ownership */
77
78/*
Jeremy Kerr4af889b2017-06-06 16:08:58 -050079 * LLMODE fields
80 */
81#define FSI_LLMODE_ASYNC 0x1
82
Jeremy Kerr2b545cd2017-06-06 16:08:42 -050083#define FSI_SLAVE_SIZE_23b 0x800000
84
Jeremy Kerr09aecfa2017-06-06 16:08:36 -050085static DEFINE_IDA(master_ida);
86
Jeremy Kerr1fa847d2017-06-06 16:08:52 -050087static const int slave_retries = 2;
88static int discard_errors;
89
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +100090static dev_t fsi_base_dev;
91static DEFINE_IDA(fsi_minor_ida);
92#define FSI_CHAR_MAX_DEVICES 0x1000
93
94/* Legacy /dev numbering: 4 devices per chip, 16 chips */
95#define FSI_CHAR_LEGACY_TOP 64
96
Jeremy Kerr014c2ab2017-06-06 16:08:40 -050097static int fsi_master_read(struct fsi_master *master, int link,
98 uint8_t slave_id, uint32_t addr, void *val, size_t size);
99static int fsi_master_write(struct fsi_master *master, int link,
100 uint8_t slave_id, uint32_t addr, const void *val, size_t size);
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500101static int fsi_master_break(struct fsi_master *master, int link);
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500102
Jeremy Kerr4efe37f2017-06-06 16:08:45 -0500103/*
104 * fsi_device_read() / fsi_device_write() / fsi_device_peek()
105 *
106 * FSI endpoint-device support
107 *
108 * Read / write / peek accessors for a client
109 *
110 * Parameters:
111 * dev: Structure passed to FSI client device drivers on probe().
112 * addr: FSI address of given device. Client should pass in its base address
113 * plus desired offset to access its register space.
114 * val: For read/peek this is the value read at the specified address. For
115 * write this is value to write to the specified address.
116 * The data in val must be FSI bus endian (big endian).
117 * size: Size in bytes of the operation. Sizes supported are 1, 2 and 4 bytes.
118 * Addresses must be aligned on size boundaries or an error will result.
119 */
120int fsi_device_read(struct fsi_device *dev, uint32_t addr, void *val,
121 size_t size)
122{
123 if (addr > dev->size || size > dev->size || addr > dev->size - size)
124 return -EINVAL;
125
126 return fsi_slave_read(dev->slave, dev->addr + addr, val, size);
127}
128EXPORT_SYMBOL_GPL(fsi_device_read);
129
130int fsi_device_write(struct fsi_device *dev, uint32_t addr, const void *val,
131 size_t size)
132{
133 if (addr > dev->size || size > dev->size || addr > dev->size - size)
134 return -EINVAL;
135
136 return fsi_slave_write(dev->slave, dev->addr + addr, val, size);
137}
138EXPORT_SYMBOL_GPL(fsi_device_write);
139
140int fsi_device_peek(struct fsi_device *dev, void *val)
141{
142 uint32_t addr = FSI_PEEK_BASE + ((dev->unit - 2) * sizeof(uint32_t));
143
144 return fsi_slave_read(dev->slave, addr, val, sizeof(uint32_t));
145}
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500146
147static void fsi_device_release(struct device *_device)
148{
149 struct fsi_device *device = to_fsi_dev(_device);
150
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030151 of_node_put(device->dev.of_node);
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500152 kfree(device);
153}
154
155static struct fsi_device *fsi_create_device(struct fsi_slave *slave)
156{
157 struct fsi_device *dev;
158
159 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
160 if (!dev)
161 return NULL;
162
163 dev->dev.parent = &slave->dev;
164 dev->dev.bus = &fsi_bus_type;
165 dev->dev.release = fsi_device_release;
166
167 return dev;
168}
169
Jeremy Kerr414c1022017-06-06 16:08:38 -0500170/* FSI slave support */
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500171static int fsi_slave_calc_addr(struct fsi_slave *slave, uint32_t *addrp,
172 uint8_t *idp)
173{
174 uint32_t addr = *addrp;
175 uint8_t id = *idp;
176
177 if (addr > slave->size)
178 return -EINVAL;
179
180 /* For 23 bit addressing, we encode the extra two bits in the slave
181 * id (and the slave's actual ID needs to be 0).
182 */
183 if (addr > 0x1fffff) {
184 if (slave->id != 0)
185 return -EINVAL;
186 id = (addr >> 21) & 0x3;
187 addr &= 0x1fffff;
188 }
189
190 *addrp = addr;
191 *idp = id;
192 return 0;
193}
194
Colin Ian Kinged50a082017-10-03 09:31:45 +0100195static int fsi_slave_report_and_clear_errors(struct fsi_slave *slave)
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500196{
197 struct fsi_master *master = slave->master;
Joel Stanley11454d62018-06-18 13:13:35 +0930198 __be32 irq, stat;
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500199 int rc, link;
200 uint8_t id;
201
202 link = slave->link;
203 id = slave->id;
204
205 rc = fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
206 &irq, sizeof(irq));
207 if (rc)
208 return rc;
209
210 rc = fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SSTAT,
211 &stat, sizeof(stat));
212 if (rc)
213 return rc;
214
Christopher Bostic638bd9a2018-02-12 15:45:46 +1030215 dev_dbg(&slave->dev, "status: 0x%08x, sisc: 0x%08x\n",
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500216 be32_to_cpu(stat), be32_to_cpu(irq));
217
218 /* clear interrupts */
219 return fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
220 &irq, sizeof(irq));
221}
222
Benjamin Herrenschmidt935f9632018-05-29 14:44:08 +1000223/* Encode slave local bus echo delay */
224static inline uint32_t fsi_smode_echodly(int x)
225{
226 return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
227}
228
229/* Encode slave local bus send delay */
230static inline uint32_t fsi_smode_senddly(int x)
231{
232 return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
233}
234
235/* Encode slave local bus clock rate ratio */
236static inline uint32_t fsi_smode_lbcrr(int x)
237{
238 return (x & FSI_SMODE_LBCRR_MASK) << FSI_SMODE_LBCRR_SHIFT;
239}
240
241/* Encode slave ID */
242static inline uint32_t fsi_smode_sid(int x)
243{
244 return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
245}
246
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000247static uint32_t fsi_slave_smode(int id, u8 t_senddly, u8 t_echodly)
Benjamin Herrenschmidt935f9632018-05-29 14:44:08 +1000248{
249 return FSI_SMODE_WSC | FSI_SMODE_ECRC
250 | fsi_smode_sid(id)
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000251 | fsi_smode_echodly(t_echodly - 1) | fsi_smode_senddly(t_senddly - 1)
Benjamin Herrenschmidt935f9632018-05-29 14:44:08 +1000252 | fsi_smode_lbcrr(0x8);
253}
254
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000255static int fsi_slave_set_smode(struct fsi_slave *slave)
Benjamin Herrenschmidt935f9632018-05-29 14:44:08 +1000256{
257 uint32_t smode;
258 __be32 data;
259
260 /* set our smode register with the slave ID field to 0; this enables
261 * extended slave addressing
262 */
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000263 smode = fsi_slave_smode(slave->id, slave->t_send_delay, slave->t_echo_delay);
Benjamin Herrenschmidt935f9632018-05-29 14:44:08 +1000264 data = cpu_to_be32(smode);
265
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000266 return fsi_master_write(slave->master, slave->link, slave->id,
267 FSI_SLAVE_BASE + FSI_SMODE,
268 &data, sizeof(data));
Benjamin Herrenschmidt935f9632018-05-29 14:44:08 +1000269}
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500270
Colin Ian Kinged50a082017-10-03 09:31:45 +0100271static int fsi_slave_handle_error(struct fsi_slave *slave, bool write,
272 uint32_t addr, size_t size)
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500273{
274 struct fsi_master *master = slave->master;
275 int rc, link;
276 uint32_t reg;
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000277 uint8_t id, send_delay, echo_delay;
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500278
279 if (discard_errors)
280 return -1;
281
282 link = slave->link;
283 id = slave->id;
284
285 dev_dbg(&slave->dev, "handling error on %s to 0x%08x[%zd]",
286 write ? "write" : "read", addr, size);
287
288 /* try a simple clear of error conditions, which may fail if we've lost
289 * communication with the slave
290 */
291 rc = fsi_slave_report_and_clear_errors(slave);
292 if (!rc)
293 return 0;
294
295 /* send a TERM and retry */
296 if (master->term) {
297 rc = master->term(master, link, id);
298 if (!rc) {
299 rc = fsi_master_read(master, link, id, 0,
300 &reg, sizeof(reg));
301 if (!rc)
302 rc = fsi_slave_report_and_clear_errors(slave);
303 if (!rc)
304 return 0;
305 }
306 }
307
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000308 send_delay = slave->t_send_delay;
309 echo_delay = slave->t_echo_delay;
310
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500311 /* getting serious, reset the slave via BREAK */
312 rc = fsi_master_break(master, link);
313 if (rc)
314 return rc;
315
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000316 slave->t_send_delay = send_delay;
317 slave->t_echo_delay = echo_delay;
318
319 rc = fsi_slave_set_smode(slave);
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500320 if (rc)
321 return rc;
322
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000323 if (master->link_config)
324 master->link_config(master, link,
325 slave->t_send_delay,
326 slave->t_echo_delay);
327
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500328 return fsi_slave_report_and_clear_errors(slave);
329}
330
Jeremy Kerrda36cad2017-06-06 16:08:50 -0500331int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500332 void *val, size_t size)
333{
334 uint8_t id = slave->id;
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500335 int rc, err_rc, i;
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500336
337 rc = fsi_slave_calc_addr(slave, &addr, &id);
338 if (rc)
339 return rc;
340
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500341 for (i = 0; i < slave_retries; i++) {
342 rc = fsi_master_read(slave->master, slave->link,
343 id, addr, val, size);
344 if (!rc)
345 break;
346
347 err_rc = fsi_slave_handle_error(slave, false, addr, size);
348 if (err_rc)
349 break;
350 }
351
352 return rc;
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500353}
Jeremy Kerrda36cad2017-06-06 16:08:50 -0500354EXPORT_SYMBOL_GPL(fsi_slave_read);
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500355
Jeremy Kerrda36cad2017-06-06 16:08:50 -0500356int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500357 const void *val, size_t size)
358{
359 uint8_t id = slave->id;
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500360 int rc, err_rc, i;
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500361
362 rc = fsi_slave_calc_addr(slave, &addr, &id);
363 if (rc)
364 return rc;
365
Jeremy Kerr1fa847d2017-06-06 16:08:52 -0500366 for (i = 0; i < slave_retries; i++) {
367 rc = fsi_master_write(slave->master, slave->link,
368 id, addr, val, size);
369 if (!rc)
370 break;
371
372 err_rc = fsi_slave_handle_error(slave, true, addr, size);
373 if (err_rc)
374 break;
375 }
376
377 return rc;
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500378}
Jeremy Kerrda36cad2017-06-06 16:08:50 -0500379EXPORT_SYMBOL_GPL(fsi_slave_write);
380
Tom Rix362fbc82022-04-03 10:09:37 -0400381int fsi_slave_claim_range(struct fsi_slave *slave,
382 uint32_t addr, uint32_t size)
Jeremy Kerrda36cad2017-06-06 16:08:50 -0500383{
384 if (addr + size < addr)
385 return -EINVAL;
386
387 if (addr + size > slave->size)
388 return -EINVAL;
389
390 /* todo: check for overlapping claims */
391 return 0;
392}
393EXPORT_SYMBOL_GPL(fsi_slave_claim_range);
394
Tom Rix362fbc82022-04-03 10:09:37 -0400395void fsi_slave_release_range(struct fsi_slave *slave,
396 uint32_t addr, uint32_t size)
Jeremy Kerrda36cad2017-06-06 16:08:50 -0500397{
398}
399EXPORT_SYMBOL_GPL(fsi_slave_release_range);
Jeremy Kerr014c2ab2017-06-06 16:08:40 -0500400
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030401static bool fsi_device_node_matches(struct device *dev, struct device_node *np,
402 uint32_t addr, uint32_t size)
403{
Rob Herring23ad7ec2023-06-09 12:30:56 -0600404 u64 paddr, psize;
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030405
Rob Herring23ad7ec2023-06-09 12:30:56 -0600406 if (of_property_read_reg(np, 0, &paddr, &psize))
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030407 return false;
408
Rob Herring23ad7ec2023-06-09 12:30:56 -0600409 if (paddr != addr)
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030410 return false;
411
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030412 if (psize != size) {
413 dev_warn(dev,
Rob Herring23ad7ec2023-06-09 12:30:56 -0600414 "node %pOF matches probed address, but not size (got 0x%llx, expected 0x%x)",
415 np, psize, size);
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030416 }
417
418 return true;
419}
420
421/* Find a matching node for the slave engine at @address, using @size bytes
422 * of space. Returns NULL if not found, or a matching node with refcount
423 * already incremented.
424 */
425static struct device_node *fsi_device_find_of_node(struct fsi_device *dev)
426{
427 struct device_node *parent, *np;
428
429 parent = dev_of_node(&dev->slave->dev);
430 if (!parent)
431 return NULL;
432
433 for_each_child_of_node(parent, np) {
434 if (fsi_device_node_matches(&dev->dev, np,
435 dev->addr, dev->size))
436 return np;
437 }
438
439 return NULL;
440}
441
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500442static int fsi_slave_scan(struct fsi_slave *slave)
443{
444 uint32_t engine_addr;
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500445 int rc, i;
446
447 /*
448 * scan engines
449 *
450 * We keep the peek mode and slave engines for the core; so start
451 * at the third slot in the configuration table. We also need to
452 * skip the chip ID entry at the start of the address space.
453 */
454 engine_addr = engine_page_size * 3;
455 for (i = 2; i < engine_page_size / sizeof(uint32_t); i++) {
456 uint8_t slots, version, type, crc;
457 struct fsi_device *dev;
Joel Stanley11454d62018-06-18 13:13:35 +0930458 uint32_t conf;
459 __be32 data;
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500460
Joel Stanley11454d62018-06-18 13:13:35 +0930461 rc = fsi_slave_read(slave, (i + 1) * sizeof(data),
462 &data, sizeof(data));
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500463 if (rc) {
464 dev_warn(&slave->dev,
465 "error reading slave registers\n");
466 return -1;
467 }
Joel Stanley11454d62018-06-18 13:13:35 +0930468 conf = be32_to_cpu(data);
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500469
470 crc = crc4(0, conf, 32);
471 if (crc) {
472 dev_warn(&slave->dev,
473 "crc error in slave register at 0x%04x\n",
474 i);
475 return -1;
476 }
477
478 slots = (conf & FSI_SLAVE_CONF_SLOTS_MASK)
479 >> FSI_SLAVE_CONF_SLOTS_SHIFT;
480 version = (conf & FSI_SLAVE_CONF_VERSION_MASK)
481 >> FSI_SLAVE_CONF_VERSION_SHIFT;
482 type = (conf & FSI_SLAVE_CONF_TYPE_MASK)
483 >> FSI_SLAVE_CONF_TYPE_SHIFT;
484
485 /*
486 * Unused address areas are marked by a zero type value; this
487 * skips the defined address areas
488 */
489 if (type != 0 && slots != 0) {
490
491 /* create device */
492 dev = fsi_create_device(slave);
493 if (!dev)
494 return -ENOMEM;
495
496 dev->slave = slave;
497 dev->engine_type = type;
498 dev->version = version;
499 dev->unit = i;
500 dev->addr = engine_addr;
501 dev->size = slots * engine_page_size;
502
Eddie Jamesf2af60b2022-02-07 10:16:40 -0600503 trace_fsi_dev_init(dev);
504
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500505 dev_dbg(&slave->dev,
506 "engine[%i]: type %x, version %x, addr %x size %x\n",
507 dev->unit, dev->engine_type, version,
508 dev->addr, dev->size);
509
510 dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x",
511 slave->master->idx, slave->link,
512 slave->id, i - 2);
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030513 dev->dev.of_node = fsi_device_find_of_node(dev);
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -0500514
515 rc = device_register(&dev->dev);
516 if (rc) {
517 dev_warn(&slave->dev, "add failed: %d\n", rc);
518 put_device(&dev->dev);
519 }
520 }
521
522 engine_addr += slots * engine_page_size;
523
524 if (!(conf & FSI_SLAVE_CONF_NEXT_MASK))
525 break;
526 }
527
528 return 0;
529}
530
Andrew Jeffery9f4c2b52019-11-08 15:49:39 +1030531static unsigned long aligned_access_size(size_t offset, size_t count)
532{
533 unsigned long offset_unit, count_unit;
534
535 /* Criteria:
536 *
537 * 1. Access size must be less than or equal to the maximum access
538 * width or the highest power-of-two factor of offset
539 * 2. Access size must be less than or equal to the amount specified by
540 * count
541 *
542 * The access width is optimal if we can calculate 1 to be strictly
543 * equal while still satisfying 2.
544 */
545
546 /* Find 1 by the bottom bit of offset (with a 4 byte access cap) */
547 offset_unit = BIT(__builtin_ctzl(offset | 4));
548
549 /* Find 2 by the top bit of count */
550 count_unit = BIT(8 * sizeof(unsigned long) - 1 - __builtin_clzl(count));
551
552 /* Constrain the maximum access width to the minimum of both criteria */
553 return BIT(__builtin_ctzl(offset_unit | count_unit));
554}
555
Jeremy Kerr125739c2017-06-06 16:08:49 -0500556static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
557 struct kobject *kobj, struct bin_attribute *attr, char *buf,
558 loff_t off, size_t count)
559{
560 struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
561 size_t total_len, read_len;
562 int rc;
563
564 if (off < 0)
565 return -EINVAL;
566
567 if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
568 return -EINVAL;
569
570 for (total_len = 0; total_len < count; total_len += read_len) {
Andrew Jeffery9f4c2b52019-11-08 15:49:39 +1030571 read_len = aligned_access_size(off, count - total_len);
Jeremy Kerr125739c2017-06-06 16:08:49 -0500572
573 rc = fsi_slave_read(slave, off, buf + total_len, read_len);
574 if (rc)
575 return rc;
576
577 off += read_len;
578 }
579
580 return count;
581}
582
583static ssize_t fsi_slave_sysfs_raw_write(struct file *file,
584 struct kobject *kobj, struct bin_attribute *attr,
585 char *buf, loff_t off, size_t count)
586{
587 struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
588 size_t total_len, write_len;
589 int rc;
590
591 if (off < 0)
592 return -EINVAL;
593
594 if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
595 return -EINVAL;
596
597 for (total_len = 0; total_len < count; total_len += write_len) {
Andrew Jeffery9f4c2b52019-11-08 15:49:39 +1030598 write_len = aligned_access_size(off, count - total_len);
Jeremy Kerr125739c2017-06-06 16:08:49 -0500599
600 rc = fsi_slave_write(slave, off, buf + total_len, write_len);
601 if (rc)
602 return rc;
603
604 off += write_len;
605 }
606
607 return count;
608}
609
Bhumika Goyal061c0952017-08-02 19:39:32 +0530610static const struct bin_attribute fsi_slave_raw_attr = {
Jeremy Kerr125739c2017-06-06 16:08:49 -0500611 .attr = {
612 .name = "raw",
613 .mode = 0600,
614 },
615 .size = 0,
616 .read = fsi_slave_sysfs_raw_read,
617 .write = fsi_slave_sysfs_raw_write,
618};
619
Jeremy Kerr2b545cd2017-06-06 16:08:42 -0500620static void fsi_slave_release(struct device *dev)
621{
622 struct fsi_slave *slave = to_fsi_slave(dev);
623
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +1000624 fsi_free_minor(slave->dev.devt);
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030625 of_node_put(dev->of_node);
Jeremy Kerr2b545cd2017-06-06 16:08:42 -0500626 kfree(slave);
627}
628
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030629static bool fsi_slave_node_matches(struct device_node *np,
630 int link, uint8_t id)
631{
Rob Herring23ad7ec2023-06-09 12:30:56 -0600632 u64 addr;
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030633
Rob Herring23ad7ec2023-06-09 12:30:56 -0600634 if (of_property_read_reg(np, 0, &addr, NULL))
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030635 return false;
636
Rob Herring23ad7ec2023-06-09 12:30:56 -0600637 return addr == (((u64)link << 32) | id);
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +1030638}
639
640/* Find a matching node for the slave at (link, id). Returns NULL if none
641 * found, or a matching node with refcount already incremented.
642 */
643static struct device_node *fsi_slave_find_of_node(struct fsi_master *master,
644 int link, uint8_t id)
645{
646 struct device_node *parent, *np;
647
648 parent = dev_of_node(&master->dev);
649 if (!parent)
650 return NULL;
651
652 for_each_child_of_node(parent, np) {
653 if (fsi_slave_node_matches(np, link, id))
654 return np;
655 }
656
657 return NULL;
658}
659
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +1000660static ssize_t cfam_read(struct file *filep, char __user *buf, size_t count,
661 loff_t *offset)
662{
663 struct fsi_slave *slave = filep->private_data;
664 size_t total_len, read_len;
665 loff_t off = *offset;
666 ssize_t rc;
667
668 if (off < 0)
669 return -EINVAL;
670
671 if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
672 return -EINVAL;
673
674 for (total_len = 0; total_len < count; total_len += read_len) {
675 __be32 data;
676
677 read_len = min_t(size_t, count, 4);
678 read_len -= off & 0x3;
679
680 rc = fsi_slave_read(slave, off, &data, read_len);
681 if (rc)
682 goto fail;
683 rc = copy_to_user(buf + total_len, &data, read_len);
684 if (rc) {
685 rc = -EFAULT;
686 goto fail;
687 }
688 off += read_len;
689 }
690 rc = count;
691 fail:
692 *offset = off;
Colin Ian King91081092021-06-03 13:28:12 +0100693 return rc;
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +1000694}
695
696static ssize_t cfam_write(struct file *filep, const char __user *buf,
697 size_t count, loff_t *offset)
698{
699 struct fsi_slave *slave = filep->private_data;
700 size_t total_len, write_len;
701 loff_t off = *offset;
702 ssize_t rc;
703
704
705 if (off < 0)
706 return -EINVAL;
707
708 if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
709 return -EINVAL;
710
711 for (total_len = 0; total_len < count; total_len += write_len) {
712 __be32 data;
713
714 write_len = min_t(size_t, count, 4);
715 write_len -= off & 0x3;
716
717 rc = copy_from_user(&data, buf + total_len, write_len);
718 if (rc) {
719 rc = -EFAULT;
720 goto fail;
721 }
722 rc = fsi_slave_write(slave, off, &data, write_len);
723 if (rc)
724 goto fail;
725 off += write_len;
726 }
727 rc = count;
728 fail:
729 *offset = off;
Colin Ian King91081092021-06-03 13:28:12 +0100730 return rc;
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +1000731}
732
733static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
734{
735 switch (whence) {
736 case SEEK_CUR:
737 break;
738 case SEEK_SET:
739 file->f_pos = offset;
740 break;
741 default:
742 return -EINVAL;
743 }
744
745 return offset;
746}
747
748static int cfam_open(struct inode *inode, struct file *file)
749{
750 struct fsi_slave *slave = container_of(inode->i_cdev, struct fsi_slave, cdev);
751
752 file->private_data = slave;
753
754 return 0;
755}
756
757static const struct file_operations cfam_fops = {
758 .owner = THIS_MODULE,
759 .open = cfam_open,
760 .llseek = cfam_llseek,
761 .read = cfam_read,
762 .write = cfam_write,
763};
764
765static ssize_t send_term_store(struct device *dev,
766 struct device_attribute *attr,
767 const char *buf, size_t count)
768{
769 struct fsi_slave *slave = to_fsi_slave(dev);
770 struct fsi_master *master = slave->master;
771
772 if (!master->term)
773 return -ENODEV;
774
775 master->term(master, slave->link, slave->id);
776 return count;
777}
778
779static DEVICE_ATTR_WO(send_term);
780
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +1000781static ssize_t slave_send_echo_show(struct device *dev,
782 struct device_attribute *attr,
783 char *buf)
784{
785 struct fsi_slave *slave = to_fsi_slave(dev);
786
787 return sprintf(buf, "%u\n", slave->t_send_delay);
788}
789
790static ssize_t slave_send_echo_store(struct device *dev,
791 struct device_attribute *attr, const char *buf, size_t count)
792{
793 struct fsi_slave *slave = to_fsi_slave(dev);
794 struct fsi_master *master = slave->master;
795 unsigned long val;
796 int rc;
797
798 if (kstrtoul(buf, 0, &val) < 0)
799 return -EINVAL;
800
801 if (val < 1 || val > 16)
802 return -EINVAL;
803
804 if (!master->link_config)
805 return -ENXIO;
806
807 /* Current HW mandates that send and echo delay are identical */
808 slave->t_send_delay = val;
809 slave->t_echo_delay = val;
810
811 rc = fsi_slave_set_smode(slave);
812 if (rc < 0)
813 return rc;
814 if (master->link_config)
815 master->link_config(master, slave->link,
816 slave->t_send_delay,
817 slave->t_echo_delay);
818
819 return count;
820}
821
822static DEVICE_ATTR(send_echo_delays, 0600,
823 slave_send_echo_show, slave_send_echo_store);
824
Benjamin Herrenschmidt0a213772018-06-20 15:16:31 +1000825static ssize_t chip_id_show(struct device *dev,
826 struct device_attribute *attr,
827 char *buf)
828{
829 struct fsi_slave *slave = to_fsi_slave(dev);
830
831 return sprintf(buf, "%d\n", slave->chip_id);
832}
833
834static DEVICE_ATTR_RO(chip_id);
835
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +1000836static ssize_t cfam_id_show(struct device *dev,
837 struct device_attribute *attr,
838 char *buf)
839{
840 struct fsi_slave *slave = to_fsi_slave(dev);
841
842 return sprintf(buf, "0x%x\n", slave->cfam_id);
843}
844
845static DEVICE_ATTR_RO(cfam_id);
846
847static struct attribute *cfam_attr[] = {
848 &dev_attr_send_echo_delays.attr,
849 &dev_attr_chip_id.attr,
850 &dev_attr_cfam_id.attr,
851 &dev_attr_send_term.attr,
852 NULL,
853};
854
855static const struct attribute_group cfam_attr_group = {
856 .attrs = cfam_attr,
857};
858
859static const struct attribute_group *cfam_attr_groups[] = {
860 &cfam_attr_group,
861 NULL,
862};
863
Greg Kroah-Hartmana9b12f8b2023-01-11 12:30:08 +0100864static char *cfam_devnode(const struct device *dev, umode_t *mode,
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +1000865 kuid_t *uid, kgid_t *gid)
866{
Greg Kroah-Hartmana9b12f8b2023-01-11 12:30:08 +0100867 const struct fsi_slave *slave = to_fsi_slave(dev);
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +1000868
869#ifdef CONFIG_FSI_NEW_DEV_NODE
870 return kasprintf(GFP_KERNEL, "fsi/cfam%d", slave->cdev_idx);
871#else
872 return kasprintf(GFP_KERNEL, "cfam%d", slave->cdev_idx);
873#endif
874}
875
876static const struct device_type cfam_type = {
877 .name = "cfam",
878 .devnode = cfam_devnode,
879 .groups = cfam_attr_groups
880};
881
Greg Kroah-Hartmana9b12f8b2023-01-11 12:30:08 +0100882static char *fsi_cdev_devnode(const struct device *dev, umode_t *mode,
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +1000883 kuid_t *uid, kgid_t *gid)
884{
885#ifdef CONFIG_FSI_NEW_DEV_NODE
886 return kasprintf(GFP_KERNEL, "fsi/%s", dev_name(dev));
887#else
888 return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
889#endif
890}
891
892const struct device_type fsi_cdev_type = {
893 .name = "fsi-cdev",
894 .devnode = fsi_cdev_devnode,
895};
896EXPORT_SYMBOL_GPL(fsi_cdev_type);
897
898/* Backward compatible /dev/ numbering in "old style" mode */
899static int fsi_adjust_index(int index)
900{
901#ifdef CONFIG_FSI_NEW_DEV_NODE
902 return index;
903#else
904 return index + 1;
905#endif
906}
907
908static int __fsi_get_new_minor(struct fsi_slave *slave, enum fsi_dev_type type,
909 dev_t *out_dev, int *out_index)
910{
911 int cid = slave->chip_id;
912 int id;
913
914 /* Check if we qualify for legacy numbering */
915 if (cid >= 0 && cid < 16 && type < 4) {
Eddie James641511b2023-06-12 14:56:52 -0500916 /*
917 * Try reserving the legacy number, which has 0 - 0x3f reserved
918 * in the ida range. cid goes up to 0xf and type contains two
919 * bits, so construct the id with the below two bit shift.
920 */
921 id = (cid << 2) | type;
Eddie James85f4e892023-06-12 14:56:53 -0500922 id = ida_alloc_range(&fsi_minor_ida, id, id, GFP_KERNEL);
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +1000923 if (id >= 0) {
924 *out_index = fsi_adjust_index(cid);
925 *out_dev = fsi_base_dev + id;
926 return 0;
927 }
928 /* Other failure */
929 if (id != -ENOSPC)
930 return id;
931 /* Fallback to non-legacy allocation */
932 }
Eddie James85f4e892023-06-12 14:56:53 -0500933 id = ida_alloc_range(&fsi_minor_ida, FSI_CHAR_LEGACY_TOP,
934 FSI_CHAR_MAX_DEVICES - 1, GFP_KERNEL);
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +1000935 if (id < 0)
936 return id;
937 *out_index = fsi_adjust_index(id);
938 *out_dev = fsi_base_dev + id;
939 return 0;
940}
941
Eddie James21930d82023-06-12 14:56:45 -0500942static const char *const fsi_dev_type_names[] = {
943 "cfam",
944 "sbefifo",
945 "scom",
946 "occ",
947};
948
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +1000949int fsi_get_new_minor(struct fsi_device *fdev, enum fsi_dev_type type,
950 dev_t *out_dev, int *out_index)
951{
Eddie James21930d82023-06-12 14:56:45 -0500952 if (fdev->dev.of_node) {
953 int aid = of_alias_get_id(fdev->dev.of_node, fsi_dev_type_names[type]);
954
955 if (aid >= 0) {
Eddie James641511b2023-06-12 14:56:52 -0500956 /* Use the same scheme as the legacy numbers. */
957 int id = (aid << 2) | type;
Eddie James21930d82023-06-12 14:56:45 -0500958
Eddie James85f4e892023-06-12 14:56:53 -0500959 id = ida_alloc_range(&fsi_minor_ida, id, id, GFP_KERNEL);
Eddie James21930d82023-06-12 14:56:45 -0500960 if (id >= 0) {
961 *out_index = aid;
962 *out_dev = fsi_base_dev + id;
963 return 0;
964 }
965
966 if (id != -ENOSPC)
967 return id;
968 }
969 }
970
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +1000971 return __fsi_get_new_minor(fdev->slave, type, out_dev, out_index);
972}
973EXPORT_SYMBOL_GPL(fsi_get_new_minor);
974
975void fsi_free_minor(dev_t dev)
976{
Eddie James85f4e892023-06-12 14:56:53 -0500977 ida_free(&fsi_minor_ida, MINOR(dev));
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +1000978}
979EXPORT_SYMBOL_GPL(fsi_free_minor);
980
Jeremy Kerr414c1022017-06-06 16:08:38 -0500981static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
982{
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +1000983 uint32_t cfam_id;
Jeremy Kerr2b545cd2017-06-06 16:08:42 -0500984 struct fsi_slave *slave;
Jeremy Kerr2b545cd2017-06-06 16:08:42 -0500985 uint8_t crc;
Eddie James196964a2020-05-20 13:17:07 -0500986 __be32 data, llmode, slbus;
Jeremy Kerr2b545cd2017-06-06 16:08:42 -0500987 int rc;
Jeremy Kerr414c1022017-06-06 16:08:38 -0500988
Jeremy Kerr2b545cd2017-06-06 16:08:42 -0500989 /* Currently, we only support single slaves on a link, and use the
990 * full 23-bit address range
991 */
992 if (id != 0)
993 return -EINVAL;
994
Joel Stanley11454d62018-06-18 13:13:35 +0930995 rc = fsi_master_read(master, link, id, 0, &data, sizeof(data));
Jeremy Kerr2b545cd2017-06-06 16:08:42 -0500996 if (rc) {
997 dev_dbg(&master->dev, "can't read slave %02x:%02x %d\n",
998 link, id, rc);
999 return -ENODEV;
1000 }
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001001 cfam_id = be32_to_cpu(data);
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001002
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001003 crc = crc4(0, cfam_id, 32);
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001004 if (crc) {
Eddie Jamesf2af60b2022-02-07 10:16:40 -06001005 trace_fsi_slave_invalid_cfam(master, link, cfam_id);
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001006 dev_warn(&master->dev, "slave %02x:%02x invalid cfam id CRC!\n",
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001007 link, id);
1008 return -EIO;
1009 }
1010
Christopher Bostic638bd9a2018-02-12 15:45:46 +10301011 dev_dbg(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001012 cfam_id, master->idx, link, id);
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001013
Jeremy Kerr4af889b2017-06-06 16:08:58 -05001014 /* If we're behind a master that doesn't provide a self-running bus
1015 * clock, put the slave into async mode
1016 */
1017 if (master->flags & FSI_MASTER_FLAG_SWCLOCK) {
1018 llmode = cpu_to_be32(FSI_LLMODE_ASYNC);
1019 rc = fsi_master_write(master, link, id,
1020 FSI_SLAVE_BASE + FSI_LLMODE,
1021 &llmode, sizeof(llmode));
1022 if (rc)
1023 dev_warn(&master->dev,
1024 "can't set llmode on slave:%02x:%02x %d\n",
1025 link, id, rc);
1026 }
1027
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001028 /* We can communicate with a slave; create the slave device and
1029 * register.
1030 */
1031 slave = kzalloc(sizeof(*slave), GFP_KERNEL);
1032 if (!slave)
1033 return -ENOMEM;
1034
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001035 dev_set_name(&slave->dev, "slave@%02x:%02x", link, id);
1036 slave->dev.type = &cfam_type;
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001037 slave->dev.parent = &master->dev;
Jeremy Kerrf6a2f8e2018-02-12 15:45:45 +10301038 slave->dev.of_node = fsi_slave_find_of_node(master, link, id);
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001039 slave->dev.release = fsi_slave_release;
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001040 device_initialize(&slave->dev);
1041 slave->cfam_id = cfam_id;
1042 slave->master = master;
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001043 slave->link = link;
1044 slave->id = id;
1045 slave->size = FSI_SLAVE_SIZE_23b;
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +10001046 slave->t_send_delay = 16;
1047 slave->t_echo_delay = 16;
1048
Benjamin Herrenschmidt0a213772018-06-20 15:16:31 +10001049 /* Get chip ID if any */
1050 slave->chip_id = -1;
1051 if (slave->dev.of_node) {
1052 uint32_t prop;
1053 if (!of_property_read_u32(slave->dev.of_node, "chip-id", &prop))
1054 slave->chip_id = prop;
1055
1056 }
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001057
Eddie James196964a2020-05-20 13:17:07 -05001058 slbus = cpu_to_be32(FSI_SLBUS_FORCE);
1059 rc = fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SLBUS,
1060 &slbus, sizeof(slbus));
1061 if (rc)
1062 dev_warn(&master->dev,
1063 "can't set slbus on slave:%02x:%02x %d\n", link, id,
1064 rc);
1065
Jeremy Kerr371975b2019-06-28 16:07:37 +08001066 rc = fsi_slave_set_smode(slave);
1067 if (rc) {
1068 dev_warn(&master->dev,
1069 "can't set smode on slave:%02x:%02x %d\n",
1070 link, id, rc);
1071 goto err_free;
1072 }
1073
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001074 /* Allocate a minor in the FSI space */
1075 rc = __fsi_get_new_minor(slave, fsi_dev_cfam, &slave->dev.devt,
1076 &slave->cdev_idx);
1077 if (rc)
1078 goto err_free;
1079
Eddie Jamesf2af60b2022-02-07 10:16:40 -06001080 trace_fsi_slave_init(slave);
1081
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001082 /* Create chardev for userspace access */
1083 cdev_init(&slave->cdev, &cfam_fops);
1084 rc = cdev_device_add(&slave->cdev, &slave->dev);
1085 if (rc) {
1086 dev_err(&slave->dev, "Error %d creating slave device\n", rc);
Jeremy Kerr371975b2019-06-28 16:07:37 +08001087 goto err_free_ida;
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001088 }
1089
Jeremy Kerr371975b2019-06-28 16:07:37 +08001090 /* Now that we have the cdev registered with the core, any fatal
1091 * failures beyond this point will need to clean up through
1092 * cdev_device_del(). Fortunately though, nothing past here is fatal.
1093 */
1094
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +10001095 if (master->link_config)
1096 master->link_config(master, link,
1097 slave->t_send_delay,
1098 slave->t_echo_delay);
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001099
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001100 /* Legacy raw file -> to be removed */
Jeremy Kerr125739c2017-06-06 16:08:49 -05001101 rc = device_create_bin_file(&slave->dev, &fsi_slave_raw_attr);
1102 if (rc)
1103 dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
1104
Benjamin Herrenschmidt0a213772018-06-20 15:16:31 +10001105
Jeremy Kerrf7ade2a2017-06-06 16:08:44 -05001106 rc = fsi_slave_scan(slave);
1107 if (rc)
1108 dev_dbg(&master->dev, "failed during slave scan with: %d\n",
1109 rc);
Jeremy Kerr2b545cd2017-06-06 16:08:42 -05001110
Jeremy Kerr371975b2019-06-28 16:07:37 +08001111 return 0;
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001112
Jeremy Kerr371975b2019-06-28 16:07:37 +08001113err_free_ida:
1114 fsi_free_minor(slave->dev.devt);
1115err_free:
1116 of_node_put(slave->dev.of_node);
1117 kfree(slave);
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001118 return rc;
Jeremy Kerr414c1022017-06-06 16:08:38 -05001119}
1120
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001121/* FSI master support */
Jeremy Kerr014c2ab2017-06-06 16:08:40 -05001122static int fsi_check_access(uint32_t addr, size_t size)
1123{
Eddie James99f039e2018-02-12 15:45:43 +10301124 if (size == 4) {
1125 if (addr & 0x3)
1126 return -EINVAL;
1127 } else if (size == 2) {
1128 if (addr & 0x1)
1129 return -EINVAL;
1130 } else if (size != 1)
Jeremy Kerr014c2ab2017-06-06 16:08:40 -05001131 return -EINVAL;
1132
1133 return 0;
1134}
1135
1136static int fsi_master_read(struct fsi_master *master, int link,
1137 uint8_t slave_id, uint32_t addr, void *val, size_t size)
1138{
1139 int rc;
1140
Jeremy Kerr66433b02017-06-06 16:08:51 -05001141 trace_fsi_master_read(master, link, slave_id, addr, size);
Jeremy Kerr014c2ab2017-06-06 16:08:40 -05001142
Jeremy Kerr66433b02017-06-06 16:08:51 -05001143 rc = fsi_check_access(addr, size);
1144 if (!rc)
1145 rc = master->read(master, link, slave_id, addr, val, size);
1146
1147 trace_fsi_master_rw_result(master, link, slave_id, addr, size,
1148 false, val, rc);
1149
1150 return rc;
Jeremy Kerr014c2ab2017-06-06 16:08:40 -05001151}
1152
1153static int fsi_master_write(struct fsi_master *master, int link,
1154 uint8_t slave_id, uint32_t addr, const void *val, size_t size)
1155{
1156 int rc;
1157
Jeremy Kerr66433b02017-06-06 16:08:51 -05001158 trace_fsi_master_write(master, link, slave_id, addr, size, val);
Jeremy Kerr014c2ab2017-06-06 16:08:40 -05001159
Jeremy Kerr66433b02017-06-06 16:08:51 -05001160 rc = fsi_check_access(addr, size);
1161 if (!rc)
1162 rc = master->write(master, link, slave_id, addr, val, size);
1163
1164 trace_fsi_master_rw_result(master, link, slave_id, addr, size,
1165 true, val, rc);
1166
1167 return rc;
Jeremy Kerr014c2ab2017-06-06 16:08:40 -05001168}
1169
Eddie Jamesb36875a2020-06-09 16:39:28 -05001170static int fsi_master_link_disable(struct fsi_master *master, int link)
1171{
1172 if (master->link_enable)
1173 return master->link_enable(master, link, false);
1174
1175 return 0;
1176}
1177
Christopher Bostic26095282017-06-06 16:08:41 -05001178static int fsi_master_link_enable(struct fsi_master *master, int link)
1179{
1180 if (master->link_enable)
Eddie James04635a32020-06-09 16:39:27 -05001181 return master->link_enable(master, link, true);
Christopher Bostic26095282017-06-06 16:08:41 -05001182
1183 return 0;
1184}
1185
1186/*
1187 * Issue a break command on this link
1188 */
1189static int fsi_master_break(struct fsi_master *master, int link)
1190{
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +10001191 int rc = 0;
1192
Jeremy Kerr66433b02017-06-06 16:08:51 -05001193 trace_fsi_master_break(master, link);
1194
Christopher Bostic26095282017-06-06 16:08:41 -05001195 if (master->send_break)
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +10001196 rc = master->send_break(master, link);
1197 if (master->link_config)
1198 master->link_config(master, link, 16, 16);
Christopher Bostic26095282017-06-06 16:08:41 -05001199
Benjamin Herrenschmidta2e7da82018-05-29 15:01:07 +10001200 return rc;
Christopher Bostic26095282017-06-06 16:08:41 -05001201}
1202
Jeremy Kerr414c1022017-06-06 16:08:38 -05001203static int fsi_master_scan(struct fsi_master *master)
1204{
Christopher Bostic26095282017-06-06 16:08:41 -05001205 int link, rc;
Jeremy Kerr414c1022017-06-06 16:08:38 -05001206
Eddie James02c8fec2023-06-12 14:56:51 -05001207 trace_fsi_master_scan(master, true);
Christopher Bostic26095282017-06-06 16:08:41 -05001208 for (link = 0; link < master->n_links; link++) {
1209 rc = fsi_master_link_enable(master, link);
1210 if (rc) {
1211 dev_dbg(&master->dev,
1212 "enable link %d failed: %d\n", link, rc);
1213 continue;
1214 }
1215 rc = fsi_master_break(master, link);
1216 if (rc) {
Eddie Jamesb36875a2020-06-09 16:39:28 -05001217 fsi_master_link_disable(master, link);
Christopher Bostic26095282017-06-06 16:08:41 -05001218 dev_dbg(&master->dev,
1219 "break to link %d failed: %d\n", link, rc);
1220 continue;
1221 }
1222
Eddie Jamesb36875a2020-06-09 16:39:28 -05001223 rc = fsi_slave_init(master, link, 0);
1224 if (rc)
1225 fsi_master_link_disable(master, link);
Christopher Bostic26095282017-06-06 16:08:41 -05001226 }
Jeremy Kerr414c1022017-06-06 16:08:38 -05001227
1228 return 0;
1229}
1230
Christopher Bosticcd0fdb52017-06-06 16:08:46 -05001231static int fsi_slave_remove_device(struct device *dev, void *arg)
1232{
1233 device_unregister(dev);
1234 return 0;
1235}
1236
1237static int fsi_master_remove_slave(struct device *dev, void *arg)
1238{
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001239 struct fsi_slave *slave = to_fsi_slave(dev);
1240
Christopher Bosticcd0fdb52017-06-06 16:08:46 -05001241 device_for_each_child(dev, NULL, fsi_slave_remove_device);
Benjamin Herrenschmidtd1dcd672018-06-21 12:34:22 +10001242 cdev_device_del(&slave->cdev, &slave->dev);
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +10001243 put_device(dev);
Christopher Bosticcd0fdb52017-06-06 16:08:46 -05001244 return 0;
1245}
1246
1247static void fsi_master_unscan(struct fsi_master *master)
1248{
Eddie James02c8fec2023-06-12 14:56:51 -05001249 trace_fsi_master_scan(master, false);
Christopher Bosticcd0fdb52017-06-06 16:08:46 -05001250 device_for_each_child(&master->dev, NULL, fsi_master_remove_slave);
1251}
1252
Jeremy Kerr15362d62018-02-12 15:45:40 +10301253int fsi_master_rescan(struct fsi_master *master)
1254{
Benjamin Herrenschmidt9840fcd2018-06-21 18:00:05 +10001255 int rc;
1256
1257 mutex_lock(&master->scan_lock);
Jeremy Kerr15362d62018-02-12 15:45:40 +10301258 fsi_master_unscan(master);
Benjamin Herrenschmidt9840fcd2018-06-21 18:00:05 +10001259 rc = fsi_master_scan(master);
1260 mutex_unlock(&master->scan_lock);
1261
1262 return rc;
Jeremy Kerr15362d62018-02-12 15:45:40 +10301263}
1264EXPORT_SYMBOL_GPL(fsi_master_rescan);
1265
Christopher Bosticcd0fdb52017-06-06 16:08:46 -05001266static ssize_t master_rescan_store(struct device *dev,
1267 struct device_attribute *attr, const char *buf, size_t count)
1268{
1269 struct fsi_master *master = to_fsi_master(dev);
1270 int rc;
1271
Jeremy Kerr15362d62018-02-12 15:45:40 +10301272 rc = fsi_master_rescan(master);
Christopher Bosticcd0fdb52017-06-06 16:08:46 -05001273 if (rc < 0)
1274 return rc;
1275
1276 return count;
1277}
1278
1279static DEVICE_ATTR(rescan, 0200, NULL, master_rescan_store);
1280
Jeremy Kerr125739c2017-06-06 16:08:49 -05001281static ssize_t master_break_store(struct device *dev,
1282 struct device_attribute *attr, const char *buf, size_t count)
1283{
1284 struct fsi_master *master = to_fsi_master(dev);
1285
1286 fsi_master_break(master, 0);
1287
1288 return count;
1289}
1290
1291static DEVICE_ATTR(break, 0200, NULL, master_break_store);
1292
Jeremy Kerrcf700ba2019-11-08 15:49:36 +10301293static struct attribute *master_attrs[] = {
1294 &dev_attr_break.attr,
1295 &dev_attr_rescan.attr,
1296 NULL
1297};
1298
1299ATTRIBUTE_GROUPS(master);
1300
kbuild test robot56ec3112019-11-08 15:49:40 +10301301static struct class fsi_master_class = {
Jeremy Kerr2e32c2d2019-11-08 15:49:35 +10301302 .name = "fsi-master",
Jeremy Kerrcf700ba2019-11-08 15:49:36 +10301303 .dev_groups = master_groups,
Jeremy Kerr2e32c2d2019-11-08 15:49:35 +10301304};
1305
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001306int fsi_master_register(struct fsi_master *master)
1307{
1308 int rc;
Christopher Bosticf3aa2c62018-02-12 15:45:49 +10301309 struct device_node *np;
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001310
Benjamin Herrenschmidt9840fcd2018-06-21 18:00:05 +10001311 mutex_init(&master->scan_lock);
Eddie Jamesadde0e12023-08-09 13:08:13 -05001312
1313 /* Alloc the requested index if it's non-zero */
1314 if (master->idx) {
1315 master->idx = ida_alloc_range(&master_ida, master->idx,
1316 master->idx, GFP_KERNEL);
1317 } else {
1318 master->idx = ida_alloc(&master_ida, GFP_KERNEL);
1319 }
1320
Jiasheng Jiang35af9fb2022-01-11 15:34:11 +08001321 if (master->idx < 0)
1322 return master->idx;
1323
Eddie Jamesadde0e12023-08-09 13:08:13 -05001324 if (!dev_name(&master->dev))
1325 dev_set_name(&master->dev, "fsi%d", master->idx);
1326
Jeremy Kerr2e32c2d2019-11-08 15:49:35 +10301327 master->dev.class = &fsi_master_class;
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001328
Eddie Jamesb1d3a8032023-08-09 13:08:14 -05001329 mutex_lock(&master->scan_lock);
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001330 rc = device_register(&master->dev);
Jeremy Kerr414c1022017-06-06 16:08:38 -05001331 if (rc) {
Eddie James85f4e892023-06-12 14:56:53 -05001332 ida_free(&master_ida, master->idx);
Eddie Jamesb1d3a8032023-08-09 13:08:14 -05001333 goto out;
Jeremy Kerr414c1022017-06-06 16:08:38 -05001334 }
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001335
Christopher Bosticf3aa2c62018-02-12 15:45:49 +10301336 np = dev_of_node(&master->dev);
Benjamin Herrenschmidt9840fcd2018-06-21 18:00:05 +10001337 if (!of_property_read_bool(np, "no-scan-on-init")) {
Christopher Bosticf3aa2c62018-02-12 15:45:49 +10301338 fsi_master_scan(master);
Benjamin Herrenschmidt9840fcd2018-06-21 18:00:05 +10001339 }
Eddie Jamesb1d3a8032023-08-09 13:08:14 -05001340out:
1341 mutex_unlock(&master->scan_lock);
1342 return rc;
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001343}
1344EXPORT_SYMBOL_GPL(fsi_master_register);
1345
1346void fsi_master_unregister(struct fsi_master *master)
1347{
Eddie Jamesadde0e12023-08-09 13:08:13 -05001348 int idx = master->idx;
Eddie James02c8fec2023-06-12 14:56:51 -05001349
Eddie Jamesadde0e12023-08-09 13:08:13 -05001350 trace_fsi_master_unregister(master);
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001351
Benjamin Herrenschmidt9840fcd2018-06-21 18:00:05 +10001352 mutex_lock(&master->scan_lock);
Christopher Bosticcd0fdb52017-06-06 16:08:46 -05001353 fsi_master_unscan(master);
Eddie Jamesadde0e12023-08-09 13:08:13 -05001354 master->n_links = 0;
Benjamin Herrenschmidt9840fcd2018-06-21 18:00:05 +10001355 mutex_unlock(&master->scan_lock);
Eddie Jamesadde0e12023-08-09 13:08:13 -05001356
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001357 device_unregister(&master->dev);
Eddie Jamesadde0e12023-08-09 13:08:13 -05001358 ida_free(&master_ida, idx);
Jeremy Kerr09aecfa2017-06-06 16:08:36 -05001359}
1360EXPORT_SYMBOL_GPL(fsi_master_unregister);
1361
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001362/* FSI core & Linux bus type definitions */
1363
Jeremy Kerrdd37eed2017-02-01 10:53:43 -06001364static int fsi_bus_match(struct device *dev, struct device_driver *drv)
1365{
1366 struct fsi_device *fsi_dev = to_fsi_dev(dev);
1367 struct fsi_driver *fsi_drv = to_fsi_drv(drv);
1368 const struct fsi_device_id *id;
1369
1370 if (!fsi_drv->id_table)
1371 return 0;
1372
1373 for (id = fsi_drv->id_table; id->engine_type; id++) {
1374 if (id->engine_type != fsi_dev->engine_type)
1375 continue;
1376 if (id->version == FSI_VERSION_ANY ||
Eddie Jamesc21d3222023-06-12 14:56:46 -05001377 id->version == fsi_dev->version) {
1378 if (drv->of_match_table) {
1379 if (of_driver_match_device(dev, drv))
1380 return 1;
1381 } else {
1382 return 1;
1383 }
1384 }
Jeremy Kerrdd37eed2017-02-01 10:53:43 -06001385 }
1386
1387 return 0;
1388}
1389
Christopher Bostic356d8002017-06-06 16:08:48 -05001390int fsi_driver_register(struct fsi_driver *fsi_drv)
1391{
1392 if (!fsi_drv)
1393 return -EINVAL;
1394 if (!fsi_drv->id_table)
1395 return -EINVAL;
1396
1397 return driver_register(&fsi_drv->drv);
1398}
1399EXPORT_SYMBOL_GPL(fsi_driver_register);
1400
1401void fsi_driver_unregister(struct fsi_driver *fsi_drv)
1402{
1403 driver_unregister(&fsi_drv->drv);
1404}
1405EXPORT_SYMBOL_GPL(fsi_driver_unregister);
1406
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001407struct bus_type fsi_bus_type = {
1408 .name = "fsi",
Jeremy Kerrdd37eed2017-02-01 10:53:43 -06001409 .match = fsi_bus_match,
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001410};
1411EXPORT_SYMBOL_GPL(fsi_bus_type);
1412
Joel Stanley496f8932017-07-11 17:00:39 +09301413static int __init fsi_init(void)
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001414{
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +10001415 int rc;
1416
1417 rc = alloc_chrdev_region(&fsi_base_dev, 0, FSI_CHAR_MAX_DEVICES, "fsi");
1418 if (rc)
1419 return rc;
1420 rc = bus_register(&fsi_bus_type);
1421 if (rc)
1422 goto fail_bus;
Jeremy Kerr2e32c2d2019-11-08 15:49:35 +10301423
1424 rc = class_register(&fsi_master_class);
1425 if (rc)
1426 goto fail_class;
1427
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +10001428 return 0;
1429
Jeremy Kerr2e32c2d2019-11-08 15:49:35 +10301430 fail_class:
1431 bus_unregister(&fsi_bus_type);
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +10001432 fail_bus:
1433 unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
1434 return rc;
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001435}
Joel Stanley496f8932017-07-11 17:00:39 +09301436postcore_initcall(fsi_init);
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001437
1438static void fsi_exit(void)
1439{
Jeremy Kerr2e32c2d2019-11-08 15:49:35 +10301440 class_unregister(&fsi_master_class);
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001441 bus_unregister(&fsi_bus_type);
Benjamin Herrenschmidt0ab5fe52018-06-20 15:22:52 +10001442 unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
1443 ida_destroy(&fsi_minor_ida);
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001444}
Jeremy Kerr0508ad12017-02-01 10:53:41 -06001445module_exit(fsi_exit);
Jeremy Kerr1fa847d2017-06-06 16:08:52 -05001446module_param(discard_errors, int, 0664);
Christopher Bosticacb7e8f2017-06-06 16:08:59 -05001447MODULE_LICENSE("GPL");
Jeremy Kerr1fa847d2017-06-06 16:08:52 -05001448MODULE_PARM_DESC(discard_errors, "Don't invoke error handling on bus accesses");