VisionFive2 Linux kernel

StarFive Tech Linux Kernel for VisionFive (JH7110) boards (mirror)

More than 9999 Commits   33 Branches   55 Tags
1802d0beecafe (Thomas Gleixner        2019-05-27 08:55:21 +0200    1) // SPDX-License-Identifier: GPL-2.0-only
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600    2) /*
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600    3)  * FSI core driver
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600    4)  *
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600    5)  * Copyright (C) IBM Corporation 2016
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600    6)  *
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000    7)  * TODO:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000    8)  *  - Rework topology
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000    9)  *  - s/chip_id/chip_loc
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   10)  *  - s/cfam/chip (cfam_id -> chip_id etc...)
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600   11)  */
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600   12) 
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500   13) #include <linux/crc4.h>
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600   14) #include <linux/device.h>
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600   15) #include <linux/fsi.h>
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500   16) #include <linux/idr.h>
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600   17) #include <linux/module.h>
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030   18) #include <linux/of.h>
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500   19) #include <linux/slab.h>
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   20) #include <linux/bitops.h>
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   21) #include <linux/cdev.h>
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   22) #include <linux/fs.h>
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   23) #include <linux/uaccess.h>
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600   24) 
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500   25) #include "fsi-master.h"
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500   26) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500   27) #define CREATE_TRACE_POINTS
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500   28) #include <trace/events/fsi.h>
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500   29) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   30) #define FSI_SLAVE_CONF_NEXT_MASK	GENMASK(31, 31)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   31) #define FSI_SLAVE_CONF_SLOTS_MASK	GENMASK(23, 16)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   32) #define FSI_SLAVE_CONF_SLOTS_SHIFT	16
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   33) #define FSI_SLAVE_CONF_VERSION_MASK	GENMASK(15, 12)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   34) #define FSI_SLAVE_CONF_VERSION_SHIFT	12
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   35) #define FSI_SLAVE_CONF_TYPE_MASK	GENMASK(11, 4)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   36) #define FSI_SLAVE_CONF_TYPE_SHIFT	4
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   37) #define FSI_SLAVE_CONF_CRC_SHIFT	4
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   38) #define FSI_SLAVE_CONF_CRC_MASK		GENMASK(3, 0)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   39) #define FSI_SLAVE_CONF_DATA_BITS	28
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   40) 
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500   41) #define FSI_PEEK_BASE			0x410
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500   42) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   43) static const int engine_page_size = 0x400;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500   44) 
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   45) #define FSI_SLAVE_BASE			0x800
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   46) 
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   47) /*
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   48)  * FSI slave engine control register offsets
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   49)  */
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500   50) #define FSI_SMODE		0x0	/* R/W: Mode register */
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500   51) #define FSI_SISC		0x8	/* R/W: Interrupt condition */
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500   52) #define FSI_SSTAT		0x14	/* R  : Slave status */
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500   53) #define FSI_SLBUS		0x30	/* W  : LBUS Ownership */
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500   54) #define FSI_LLMODE		0x100	/* R/W: Link layer mode register */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   55) 
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   56) /*
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   57)  * SMODE fields
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   58)  */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   59) #define FSI_SMODE_WSC		0x80000000	/* Warm start done */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   60) #define FSI_SMODE_ECRC		0x20000000	/* Hw CRC check */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   61) #define FSI_SMODE_SID_SHIFT	24		/* ID shift */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   62) #define FSI_SMODE_SID_MASK	3		/* ID Mask */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   63) #define FSI_SMODE_ED_SHIFT	20		/* Echo delay shift */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   64) #define FSI_SMODE_ED_MASK	0xf		/* Echo delay mask */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   65) #define FSI_SMODE_SD_SHIFT	16		/* Send delay shift */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   66) #define FSI_SMODE_SD_MASK	0xf		/* Send delay mask */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   67) #define FSI_SMODE_LBCRR_SHIFT	8		/* Clk ratio shift */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   68) #define FSI_SMODE_LBCRR_MASK	0xf		/* Clk ratio mask */
2b37c3e285f9d (Christopher Bostic     2017-06-06 16:08:43 -0500   69) 
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500   70) /*
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500   71)  * SLBUS fields
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500   72)  */
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500   73) #define FSI_SLBUS_FORCE		0x80000000	/* Force LBUS ownership */
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500   74) 
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500   75) /*
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500   76)  * LLMODE fields
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500   77)  */
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500   78) #define FSI_LLMODE_ASYNC	0x1
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500   79) 
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500   80) #define FSI_SLAVE_SIZE_23b		0x800000
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500   81) 
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500   82) static DEFINE_IDA(master_ida);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500   83) 
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500   84) struct fsi_slave {
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500   85) 	struct device		dev;
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500   86) 	struct fsi_master	*master;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   87) 	struct cdev		cdev;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   88) 	int			cdev_idx;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   89) 	int			id;	/* FSI address */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   90) 	int			link;	/* FSI link# */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000   91) 	u32			cfam_id;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000   92) 	int			chip_id;
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500   93) 	uint32_t		size;	/* size of slave address space */
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000   94) 	u8			t_send_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000   95) 	u8			t_echo_delay;
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500   96) };
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500   97) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500   98) #define to_fsi_master(d) container_of(d, struct fsi_master, dev)
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500   99) #define to_fsi_slave(d) container_of(d, struct fsi_slave, dev)
faf0b116dec11 (Jeremy Kerr            2017-06-06 16:08:37 -0500  100) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  101) static const int slave_retries = 2;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  102) static int discard_errors;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  103) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  104) static dev_t fsi_base_dev;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  105) static DEFINE_IDA(fsi_minor_ida);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  106) #define FSI_CHAR_MAX_DEVICES	0x1000
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  107) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  108) /* Legacy /dev numbering: 4 devices per chip, 16 chips */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  109) #define FSI_CHAR_LEGACY_TOP	64
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  110) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  111) static int fsi_master_read(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  112) 		uint8_t slave_id, uint32_t addr, void *val, size_t size);
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  113) static int fsi_master_write(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  114) 		uint8_t slave_id, uint32_t addr, const void *val, size_t size);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  115) static int fsi_master_break(struct fsi_master *master, int link);
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  116) 
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  117) /*
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  118)  * fsi_device_read() / fsi_device_write() / fsi_device_peek()
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  119)  *
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  120)  * FSI endpoint-device support
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  121)  *
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  122)  * Read / write / peek accessors for a client
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  123)  *
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  124)  * Parameters:
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  125)  * dev:  Structure passed to FSI client device drivers on probe().
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  126)  * addr: FSI address of given device.  Client should pass in its base address
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  127)  *       plus desired offset to access its register space.
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  128)  * val:  For read/peek this is the value read at the specified address. For
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  129)  *       write this is value to write to the specified address.
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  130)  *       The data in val must be FSI bus endian (big endian).
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  131)  * size: Size in bytes of the operation.  Sizes supported are 1, 2 and 4 bytes.
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  132)  *       Addresses must be aligned on size boundaries or an error will result.
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  133)  */
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  134) int fsi_device_read(struct fsi_device *dev, uint32_t addr, void *val,
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  135) 		size_t size)
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  136) {
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  137) 	if (addr > dev->size || size > dev->size || addr > dev->size - size)
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  138) 		return -EINVAL;
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  139) 
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  140) 	return fsi_slave_read(dev->slave, dev->addr + addr, val, size);
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  141) }
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  142) EXPORT_SYMBOL_GPL(fsi_device_read);
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  143) 
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  144) int fsi_device_write(struct fsi_device *dev, uint32_t addr, const void *val,
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  145) 		size_t size)
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  146) {
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  147) 	if (addr > dev->size || size > dev->size || addr > dev->size - size)
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  148) 		return -EINVAL;
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  149) 
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  150) 	return fsi_slave_write(dev->slave, dev->addr + addr, val, size);
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  151) }
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  152) EXPORT_SYMBOL_GPL(fsi_device_write);
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  153) 
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  154) int fsi_device_peek(struct fsi_device *dev, void *val)
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  155) {
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  156) 	uint32_t addr = FSI_PEEK_BASE + ((dev->unit - 2) * sizeof(uint32_t));
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  157) 
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  158) 	return fsi_slave_read(dev->slave, addr, val, sizeof(uint32_t));
4efe37f4c4efc (Jeremy Kerr            2017-06-06 16:08:45 -0500  159) }
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  160) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  161) static void fsi_device_release(struct device *_device)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  162) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  163) 	struct fsi_device *device = to_fsi_dev(_device);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  164) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  165) 	of_node_put(device->dev.of_node);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  166) 	kfree(device);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  167) }
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  168) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  169) static struct fsi_device *fsi_create_device(struct fsi_slave *slave)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  170) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  171) 	struct fsi_device *dev;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  172) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  173) 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  174) 	if (!dev)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  175) 		return NULL;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  176) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  177) 	dev->dev.parent = &slave->dev;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  178) 	dev->dev.bus = &fsi_bus_type;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  179) 	dev->dev.release = fsi_device_release;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  180) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  181) 	return dev;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  182) }
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  183) 
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500  184) /* FSI slave support */
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  185) static int fsi_slave_calc_addr(struct fsi_slave *slave, uint32_t *addrp,
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  186) 		uint8_t *idp)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  187) {
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  188) 	uint32_t addr = *addrp;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  189) 	uint8_t id = *idp;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  190) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  191) 	if (addr > slave->size)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  192) 		return -EINVAL;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  193) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  194) 	/* For 23 bit addressing, we encode the extra two bits in the slave
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  195) 	 * id (and the slave's actual ID needs to be 0).
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  196) 	 */
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  197) 	if (addr > 0x1fffff) {
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  198) 		if (slave->id != 0)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  199) 			return -EINVAL;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  200) 		id = (addr >> 21) & 0x3;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  201) 		addr &= 0x1fffff;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  202) 	}
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  203) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  204) 	*addrp = addr;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  205) 	*idp = id;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  206) 	return 0;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  207) }
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  208) 
ed50a0890eaa8 (Colin Ian King         2017-10-03 09:31:45 +0100  209) static int fsi_slave_report_and_clear_errors(struct fsi_slave *slave)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  210) {
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  211) 	struct fsi_master *master = slave->master;
11454d6dc8181 (Joel Stanley           2018-06-18 13:13:35 +0930  212) 	__be32 irq, stat;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  213) 	int rc, link;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  214) 	uint8_t id;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  215) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  216) 	link = slave->link;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  217) 	id = slave->id;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  218) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  219) 	rc = fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  220) 			&irq, sizeof(irq));
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  221) 	if (rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  222) 		return rc;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  223) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  224) 	rc =  fsi_master_read(master, link, id, FSI_SLAVE_BASE + FSI_SSTAT,
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  225) 			&stat, sizeof(stat));
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  226) 	if (rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  227) 		return rc;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  228) 
638bd9ac847e8 (Christopher Bostic     2018-02-12 15:45:46 +1030  229) 	dev_dbg(&slave->dev, "status: 0x%08x, sisc: 0x%08x\n",
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  230) 			be32_to_cpu(stat), be32_to_cpu(irq));
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  231) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  232) 	/* clear interrupts */
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  233) 	return fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SISC,
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  234) 			&irq, sizeof(irq));
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  235) }
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  236) 
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  237) /* Encode slave local bus echo delay */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  238) static inline uint32_t fsi_smode_echodly(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  239) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  240) 	return (x & FSI_SMODE_ED_MASK) << FSI_SMODE_ED_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  241) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  242) 
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  243) /* Encode slave local bus send delay */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  244) static inline uint32_t fsi_smode_senddly(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  245) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  246) 	return (x & FSI_SMODE_SD_MASK) << FSI_SMODE_SD_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  247) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  248) 
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  249) /* Encode slave local bus clock rate ratio */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  250) static inline uint32_t fsi_smode_lbcrr(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  251) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  252) 	return (x & FSI_SMODE_LBCRR_MASK) << FSI_SMODE_LBCRR_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  253) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  254) 
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  255) /* Encode slave ID */
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  256) static inline uint32_t fsi_smode_sid(int x)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  257) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  258) 	return (x & FSI_SMODE_SID_MASK) << FSI_SMODE_SID_SHIFT;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  259) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  260) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  261) static uint32_t fsi_slave_smode(int id, u8 t_senddly, u8 t_echodly)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  262) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  263) 	return FSI_SMODE_WSC | FSI_SMODE_ECRC
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  264) 		| fsi_smode_sid(id)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  265) 		| fsi_smode_echodly(t_echodly - 1) | fsi_smode_senddly(t_senddly - 1)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  266) 		| fsi_smode_lbcrr(0x8);
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  267) }
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  268) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  269) static int fsi_slave_set_smode(struct fsi_slave *slave)
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  270) {
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  271) 	uint32_t smode;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  272) 	__be32 data;
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  273) 
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  274) 	/* set our smode register with the slave ID field to 0; this enables
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  275) 	 * extended slave addressing
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  276) 	 */
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  277) 	smode = fsi_slave_smode(slave->id, slave->t_send_delay, slave->t_echo_delay);
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  278) 	data = cpu_to_be32(smode);
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  279) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  280) 	return fsi_master_write(slave->master, slave->link, slave->id,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  281) 				FSI_SLAVE_BASE + FSI_SMODE,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  282) 				&data, sizeof(data));
935f9636389f0 (Benjamin Herrenschmidt 2018-05-29 14:44:08 +1000  283) }
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  284) 
ed50a0890eaa8 (Colin Ian King         2017-10-03 09:31:45 +0100  285) static int fsi_slave_handle_error(struct fsi_slave *slave, bool write,
ed50a0890eaa8 (Colin Ian King         2017-10-03 09:31:45 +0100  286) 				  uint32_t addr, size_t size)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  287) {
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  288) 	struct fsi_master *master = slave->master;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  289) 	int rc, link;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  290) 	uint32_t reg;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  291) 	uint8_t id, send_delay, echo_delay;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  292) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  293) 	if (discard_errors)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  294) 		return -1;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  295) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  296) 	link = slave->link;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  297) 	id = slave->id;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  298) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  299) 	dev_dbg(&slave->dev, "handling error on %s to 0x%08x[%zd]",
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  300) 			write ? "write" : "read", addr, size);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  301) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  302) 	/* try a simple clear of error conditions, which may fail if we've lost
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  303) 	 * communication with the slave
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  304) 	 */
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  305) 	rc = fsi_slave_report_and_clear_errors(slave);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  306) 	if (!rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  307) 		return 0;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  308) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  309) 	/* send a TERM and retry */
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  310) 	if (master->term) {
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  311) 		rc = master->term(master, link, id);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  312) 		if (!rc) {
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  313) 			rc = fsi_master_read(master, link, id, 0,
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  314) 					&reg, sizeof(reg));
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  315) 			if (!rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  316) 				rc = fsi_slave_report_and_clear_errors(slave);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  317) 			if (!rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  318) 				return 0;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  319) 		}
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  320) 	}
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  321) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  322) 	send_delay = slave->t_send_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  323) 	echo_delay = slave->t_echo_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  324) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  325) 	/* getting serious, reset the slave via BREAK */
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  326) 	rc = fsi_master_break(master, link);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  327) 	if (rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  328) 		return rc;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  329) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  330) 	slave->t_send_delay = send_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  331) 	slave->t_echo_delay = echo_delay;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  332) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  333) 	rc = fsi_slave_set_smode(slave);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  334) 	if (rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  335) 		return rc;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  336) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  337) 	if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  338) 		master->link_config(master, link,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  339) 				    slave->t_send_delay,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  340) 				    slave->t_echo_delay);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  341) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  342) 	return fsi_slave_report_and_clear_errors(slave);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  343) }
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  344) 
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  345) int fsi_slave_read(struct fsi_slave *slave, uint32_t addr,
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  346) 			void *val, size_t size)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  347) {
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  348) 	uint8_t id = slave->id;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  349) 	int rc, err_rc, i;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  350) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  351) 	rc = fsi_slave_calc_addr(slave, &addr, &id);
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  352) 	if (rc)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  353) 		return rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  354) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  355) 	for (i = 0; i < slave_retries; i++) {
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  356) 		rc = fsi_master_read(slave->master, slave->link,
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  357) 				id, addr, val, size);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  358) 		if (!rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  359) 			break;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  360) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  361) 		err_rc = fsi_slave_handle_error(slave, false, addr, size);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  362) 		if (err_rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  363) 			break;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  364) 	}
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  365) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  366) 	return rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  367) }
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  368) EXPORT_SYMBOL_GPL(fsi_slave_read);
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  369) 
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  370) int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  371) 			const void *val, size_t size)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  372) {
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  373) 	uint8_t id = slave->id;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  374) 	int rc, err_rc, i;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  375) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  376) 	rc = fsi_slave_calc_addr(slave, &addr, &id);
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  377) 	if (rc)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  378) 		return rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  379) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  380) 	for (i = 0; i < slave_retries; i++) {
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  381) 		rc = fsi_master_write(slave->master, slave->link,
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  382) 				id, addr, val, size);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  383) 		if (!rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  384) 			break;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  385) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  386) 		err_rc = fsi_slave_handle_error(slave, true, addr, size);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  387) 		if (err_rc)
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  388) 			break;
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  389) 	}
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  390) 
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500  391) 	return rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  392) }
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  393) EXPORT_SYMBOL_GPL(fsi_slave_write);
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  394) 
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  395) extern int fsi_slave_claim_range(struct fsi_slave *slave,
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  396) 		uint32_t addr, uint32_t size)
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  397) {
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  398) 	if (addr + size < addr)
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  399) 		return -EINVAL;
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  400) 
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  401) 	if (addr + size > slave->size)
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  402) 		return -EINVAL;
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  403) 
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  404) 	/* todo: check for overlapping claims */
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  405) 	return 0;
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  406) }
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  407) EXPORT_SYMBOL_GPL(fsi_slave_claim_range);
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  408) 
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  409) extern void fsi_slave_release_range(struct fsi_slave *slave,
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  410) 		uint32_t addr, uint32_t size)
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  411) {
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  412) }
da36cadf89a75 (Jeremy Kerr            2017-06-06 16:08:50 -0500  413) EXPORT_SYMBOL_GPL(fsi_slave_release_range);
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500  414) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  415) static bool fsi_device_node_matches(struct device *dev, struct device_node *np,
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  416) 		uint32_t addr, uint32_t size)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  417) {
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  418) 	unsigned int len, na, ns;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  419) 	const __be32 *prop;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  420) 	uint32_t psize;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  421) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  422) 	na = of_n_addr_cells(np);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  423) 	ns = of_n_size_cells(np);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  424) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  425) 	if (na != 1 || ns != 1)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  426) 		return false;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  427) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  428) 	prop = of_get_property(np, "reg", &len);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  429) 	if (!prop || len != 8)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  430) 		return false;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  431) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  432) 	if (of_read_number(prop, 1) != addr)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  433) 		return false;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  434) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  435) 	psize = of_read_number(prop + 1, 1);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  436) 	if (psize != size) {
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  437) 		dev_warn(dev,
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  438) 			"node %s matches probed address, but not size (got 0x%x, expected 0x%x)",
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  439) 			of_node_full_name(np), psize, size);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  440) 	}
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  441) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  442) 	return true;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  443) }
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  444) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  445) /* Find a matching node for the slave engine at @address, using @size bytes
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  446)  * of space. Returns NULL if not found, or a matching node with refcount
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  447)  * already incremented.
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  448)  */
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  449) static struct device_node *fsi_device_find_of_node(struct fsi_device *dev)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  450) {
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  451) 	struct device_node *parent, *np;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  452) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  453) 	parent = dev_of_node(&dev->slave->dev);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  454) 	if (!parent)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  455) 		return NULL;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  456) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  457) 	for_each_child_of_node(parent, np) {
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  458) 		if (fsi_device_node_matches(&dev->dev, np,
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  459) 					dev->addr, dev->size))
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  460) 			return np;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  461) 	}
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  462) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  463) 	return NULL;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  464) }
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  465) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  466) static int fsi_slave_scan(struct fsi_slave *slave)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  467) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  468) 	uint32_t engine_addr;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  469) 	int rc, i;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  470) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  471) 	/*
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  472) 	 * scan engines
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  473) 	 *
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  474) 	 * We keep the peek mode and slave engines for the core; so start
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  475) 	 * at the third slot in the configuration table. We also need to
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  476) 	 * skip the chip ID entry at the start of the address space.
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  477) 	 */
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  478) 	engine_addr = engine_page_size * 3;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  479) 	for (i = 2; i < engine_page_size / sizeof(uint32_t); i++) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  480) 		uint8_t slots, version, type, crc;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  481) 		struct fsi_device *dev;
11454d6dc8181 (Joel Stanley           2018-06-18 13:13:35 +0930  482) 		uint32_t conf;
11454d6dc8181 (Joel Stanley           2018-06-18 13:13:35 +0930  483) 		__be32 data;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  484) 
11454d6dc8181 (Joel Stanley           2018-06-18 13:13:35 +0930  485) 		rc = fsi_slave_read(slave, (i + 1) * sizeof(data),
11454d6dc8181 (Joel Stanley           2018-06-18 13:13:35 +0930  486) 				&data, sizeof(data));
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  487) 		if (rc) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  488) 			dev_warn(&slave->dev,
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  489) 				"error reading slave registers\n");
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  490) 			return -1;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  491) 		}
11454d6dc8181 (Joel Stanley           2018-06-18 13:13:35 +0930  492) 		conf = be32_to_cpu(data);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  493) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  494) 		crc = crc4(0, conf, 32);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  495) 		if (crc) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  496) 			dev_warn(&slave->dev,
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  497) 				"crc error in slave register at 0x%04x\n",
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  498) 				i);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  499) 			return -1;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  500) 		}
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  501) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  502) 		slots = (conf & FSI_SLAVE_CONF_SLOTS_MASK)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  503) 			>> FSI_SLAVE_CONF_SLOTS_SHIFT;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  504) 		version = (conf & FSI_SLAVE_CONF_VERSION_MASK)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  505) 			>> FSI_SLAVE_CONF_VERSION_SHIFT;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  506) 		type = (conf & FSI_SLAVE_CONF_TYPE_MASK)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  507) 			>> FSI_SLAVE_CONF_TYPE_SHIFT;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  508) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  509) 		/*
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  510) 		 * Unused address areas are marked by a zero type value; this
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  511) 		 * skips the defined address areas
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  512) 		 */
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  513) 		if (type != 0 && slots != 0) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  514) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  515) 			/* create device */
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  516) 			dev = fsi_create_device(slave);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  517) 			if (!dev)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  518) 				return -ENOMEM;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  519) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  520) 			dev->slave = slave;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  521) 			dev->engine_type = type;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  522) 			dev->version = version;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  523) 			dev->unit = i;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  524) 			dev->addr = engine_addr;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  525) 			dev->size = slots * engine_page_size;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  526) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  527) 			dev_dbg(&slave->dev,
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  528) 			"engine[%i]: type %x, version %x, addr %x size %x\n",
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  529) 					dev->unit, dev->engine_type, version,
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  530) 					dev->addr, dev->size);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  531) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  532) 			dev_set_name(&dev->dev, "%02x:%02x:%02x:%02x",
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  533) 					slave->master->idx, slave->link,
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  534) 					slave->id, i - 2);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  535) 			dev->dev.of_node = fsi_device_find_of_node(dev);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  536) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  537) 			rc = device_register(&dev->dev);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  538) 			if (rc) {
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  539) 				dev_warn(&slave->dev, "add failed: %d\n", rc);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  540) 				put_device(&dev->dev);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  541) 			}
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  542) 		}
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  543) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  544) 		engine_addr += slots * engine_page_size;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  545) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  546) 		if (!(conf & FSI_SLAVE_CONF_NEXT_MASK))
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  547) 			break;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  548) 	}
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  549) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  550) 	return 0;
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  551) }
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500  552) 
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  553) static unsigned long aligned_access_size(size_t offset, size_t count)
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  554) {
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  555) 	unsigned long offset_unit, count_unit;
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  556) 
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  557) 	/* Criteria:
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  558) 	 *
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  559) 	 * 1. Access size must be less than or equal to the maximum access
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  560) 	 *    width or the highest power-of-two factor of offset
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  561) 	 * 2. Access size must be less than or equal to the amount specified by
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  562) 	 *    count
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  563) 	 *
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  564) 	 * The access width is optimal if we can calculate 1 to be strictly
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  565) 	 * equal while still satisfying 2.
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  566) 	 */
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  567) 
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  568) 	/* Find 1 by the bottom bit of offset (with a 4 byte access cap) */
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  569) 	offset_unit = BIT(__builtin_ctzl(offset | 4));
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  570) 
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  571) 	/* Find 2 by the top bit of count */
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  572) 	count_unit = BIT(8 * sizeof(unsigned long) - 1 - __builtin_clzl(count));
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  573) 
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  574) 	/* Constrain the maximum access width to the minimum of both criteria */
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  575) 	return BIT(__builtin_ctzl(offset_unit | count_unit));
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  576) }
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  577) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  578) static ssize_t fsi_slave_sysfs_raw_read(struct file *file,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  579) 		struct kobject *kobj, struct bin_attribute *attr, char *buf,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  580) 		loff_t off, size_t count)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  581) {
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  582) 	struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  583) 	size_t total_len, read_len;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  584) 	int rc;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  585) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  586) 	if (off < 0)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  587) 		return -EINVAL;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  588) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  589) 	if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  590) 		return -EINVAL;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  591) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  592) 	for (total_len = 0; total_len < count; total_len += read_len) {
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  593) 		read_len = aligned_access_size(off, count - total_len);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  594) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  595) 		rc = fsi_slave_read(slave, off, buf + total_len, read_len);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  596) 		if (rc)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  597) 			return rc;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  598) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  599) 		off += read_len;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  600) 	}
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  601) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  602) 	return count;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  603) }
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  604) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  605) static ssize_t fsi_slave_sysfs_raw_write(struct file *file,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  606) 		struct kobject *kobj, struct bin_attribute *attr,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  607) 		char *buf, loff_t off, size_t count)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  608) {
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  609) 	struct fsi_slave *slave = to_fsi_slave(kobj_to_dev(kobj));
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  610) 	size_t total_len, write_len;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  611) 	int rc;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  612) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  613) 	if (off < 0)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  614) 		return -EINVAL;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  615) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  616) 	if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  617) 		return -EINVAL;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  618) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  619) 	for (total_len = 0; total_len < count; total_len += write_len) {
9f4c2b516b4f0 (Andrew Jeffery         2019-11-08 15:49:39 +1030  620) 		write_len = aligned_access_size(off, count - total_len);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  621) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  622) 		rc = fsi_slave_write(slave, off, buf + total_len, write_len);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  623) 		if (rc)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  624) 			return rc;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  625) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  626) 		off += write_len;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  627) 	}
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  628) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  629) 	return count;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  630) }
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  631) 
061c0958de2e5 (Bhumika Goyal          2017-08-02 19:39:32 +0530  632) static const struct bin_attribute fsi_slave_raw_attr = {
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  633) 	.attr = {
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  634) 		.name = "raw",
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  635) 		.mode = 0600,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  636) 	},
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  637) 	.size = 0,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  638) 	.read = fsi_slave_sysfs_raw_read,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  639) 	.write = fsi_slave_sysfs_raw_write,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  640) };
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500  641) 
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  642) static void fsi_slave_release(struct device *dev)
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  643) {
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  644) 	struct fsi_slave *slave = to_fsi_slave(dev);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  645) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  646) 	fsi_free_minor(slave->dev.devt);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  647) 	of_node_put(dev->of_node);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  648) 	kfree(slave);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  649) }
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  650) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  651) static bool fsi_slave_node_matches(struct device_node *np,
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  652) 		int link, uint8_t id)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  653) {
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  654) 	unsigned int len, na, ns;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  655) 	const __be32 *prop;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  656) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  657) 	na = of_n_addr_cells(np);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  658) 	ns = of_n_size_cells(np);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  659) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  660) 	/* Ensure we have the correct format for addresses and sizes in
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  661) 	 * reg properties
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  662) 	 */
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  663) 	if (na != 2 || ns != 0)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  664) 		return false;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  665) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  666) 	prop = of_get_property(np, "reg", &len);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  667) 	if (!prop || len != 8)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  668) 		return false;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  669) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  670) 	return (of_read_number(prop, 1) == link) &&
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  671) 		(of_read_number(prop + 1, 1) == id);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  672) }
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  673) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  674) /* Find a matching node for the slave at (link, id). Returns NULL if none
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  675)  * found, or a matching node with refcount already incremented.
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  676)  */
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  677) static struct device_node *fsi_slave_find_of_node(struct fsi_master *master,
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  678) 		int link, uint8_t id)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  679) {
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  680) 	struct device_node *parent, *np;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  681) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  682) 	parent = dev_of_node(&master->dev);
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  683) 	if (!parent)
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  684) 		return NULL;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  685) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  686) 	for_each_child_of_node(parent, np) {
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  687) 		if (fsi_slave_node_matches(np, link, id))
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  688) 			return np;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  689) 	}
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  690) 
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  691) 	return NULL;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  692) }
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030  693) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  694) static ssize_t cfam_read(struct file *filep, char __user *buf, size_t count,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  695) 			 loff_t *offset)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  696) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  697) 	struct fsi_slave *slave = filep->private_data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  698) 	size_t total_len, read_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  699) 	loff_t off = *offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  700) 	ssize_t rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  701) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  702) 	if (off < 0)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  703) 		return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  704) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  705) 	if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  706) 		return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  707) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  708) 	for (total_len = 0; total_len < count; total_len += read_len) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  709) 		__be32 data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  710) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  711) 		read_len = min_t(size_t, count, 4);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  712) 		read_len -= off & 0x3;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  713) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  714) 		rc = fsi_slave_read(slave, off, &data, read_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  715) 		if (rc)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  716) 			goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  717) 		rc = copy_to_user(buf + total_len, &data, read_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  718) 		if (rc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  719) 			rc = -EFAULT;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  720) 			goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  721) 		}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  722) 		off += read_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  723) 	}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  724) 	rc = count;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  725)  fail:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  726) 	*offset = off;
910810945707f (Colin Ian King         2021-06-03 13:28:12 +0100  727) 	return rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  728) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  729) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  730) static ssize_t cfam_write(struct file *filep, const char __user *buf,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  731) 			  size_t count, loff_t *offset)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  732) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  733) 	struct fsi_slave *slave = filep->private_data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  734) 	size_t total_len, write_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  735) 	loff_t off = *offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  736) 	ssize_t rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  737) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  738) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  739) 	if (off < 0)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  740) 		return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  741) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  742) 	if (off > 0xffffffff || count > 0xffffffff || off + count > 0xffffffff)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  743) 		return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  744) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  745) 	for (total_len = 0; total_len < count; total_len += write_len) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  746) 		__be32 data;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  747) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  748) 		write_len = min_t(size_t, count, 4);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  749) 		write_len -= off & 0x3;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  750) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  751) 		rc = copy_from_user(&data, buf + total_len, write_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  752) 		if (rc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  753) 			rc = -EFAULT;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  754) 			goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  755) 		}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  756) 		rc = fsi_slave_write(slave, off, &data, write_len);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  757) 		if (rc)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  758) 			goto fail;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  759) 		off += write_len;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  760) 	}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  761) 	rc = count;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  762)  fail:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  763) 	*offset = off;
910810945707f (Colin Ian King         2021-06-03 13:28:12 +0100  764) 	return rc;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  765) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  766) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  767) static loff_t cfam_llseek(struct file *file, loff_t offset, int whence)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  768) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  769) 	switch (whence) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  770) 	case SEEK_CUR:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  771) 		break;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  772) 	case SEEK_SET:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  773) 		file->f_pos = offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  774) 		break;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  775) 	default:
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  776) 		return -EINVAL;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  777) 	}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  778) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  779) 	return offset;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  780) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  781) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  782) static int cfam_open(struct inode *inode, struct file *file)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  783) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  784) 	struct fsi_slave *slave = container_of(inode->i_cdev, struct fsi_slave, cdev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  785) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  786) 	file->private_data = slave;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  787) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  788) 	return 0;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  789) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  790) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  791) static const struct file_operations cfam_fops = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  792) 	.owner		= THIS_MODULE,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  793) 	.open		= cfam_open,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  794) 	.llseek		= cfam_llseek,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  795) 	.read		= cfam_read,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  796) 	.write		= cfam_write,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  797) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  798) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  799) static ssize_t send_term_store(struct device *dev,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  800) 			       struct device_attribute *attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  801) 			       const char *buf, size_t count)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  802) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  803) 	struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  804) 	struct fsi_master *master = slave->master;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  805) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  806) 	if (!master->term)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  807) 		return -ENODEV;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  808) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  809) 	master->term(master, slave->link, slave->id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  810) 	return count;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  811) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  812) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  813) static DEVICE_ATTR_WO(send_term);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  814) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  815) static ssize_t slave_send_echo_show(struct device *dev,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  816) 				    struct device_attribute *attr,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  817) 				    char *buf)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  818) {
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  819) 	struct fsi_slave *slave = to_fsi_slave(dev);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  820) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  821) 	return sprintf(buf, "%u\n", slave->t_send_delay);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  822) }
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  823) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  824) static ssize_t slave_send_echo_store(struct device *dev,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  825) 		struct device_attribute *attr, const char *buf, size_t count)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  826) {
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  827) 	struct fsi_slave *slave = to_fsi_slave(dev);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  828) 	struct fsi_master *master = slave->master;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  829) 	unsigned long val;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  830) 	int rc;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  831) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  832) 	if (kstrtoul(buf, 0, &val) < 0)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  833) 		return -EINVAL;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  834) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  835) 	if (val < 1 || val > 16)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  836) 		return -EINVAL;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  837) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  838) 	if (!master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  839) 		return -ENXIO;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  840) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  841) 	/* Current HW mandates that send and echo delay are identical */
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  842) 	slave->t_send_delay = val;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  843) 	slave->t_echo_delay = val;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  844) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  845) 	rc = fsi_slave_set_smode(slave);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  846) 	if (rc < 0)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  847) 		return rc;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  848) 	if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  849) 		master->link_config(master, slave->link,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  850) 				    slave->t_send_delay,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  851) 				    slave->t_echo_delay);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  852) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  853) 	return count;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  854) }
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  855) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  856) static DEVICE_ATTR(send_echo_delays, 0600,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  857) 		   slave_send_echo_show, slave_send_echo_store);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000  858) 
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  859) static ssize_t chip_id_show(struct device *dev,
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  860) 			    struct device_attribute *attr,
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  861) 			    char *buf)
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  862) {
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  863) 	struct fsi_slave *slave = to_fsi_slave(dev);
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  864) 
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  865) 	return sprintf(buf, "%d\n", slave->chip_id);
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  866) }
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  867) 
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  868) static DEVICE_ATTR_RO(chip_id);
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000  869) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  870) static ssize_t cfam_id_show(struct device *dev,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  871) 			    struct device_attribute *attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  872) 			    char *buf)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  873) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  874) 	struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  875) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  876) 	return sprintf(buf, "0x%x\n", slave->cfam_id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  877) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  878) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  879) static DEVICE_ATTR_RO(cfam_id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  880) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  881) static struct attribute *cfam_attr[] = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  882) 	&dev_attr_send_echo_delays.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  883) 	&dev_attr_chip_id.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  884) 	&dev_attr_cfam_id.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  885) 	&dev_attr_send_term.attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  886) 	NULL,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  887) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  888) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  889) static const struct attribute_group cfam_attr_group = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  890) 	.attrs = cfam_attr,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  891) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  892) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  893) static const struct attribute_group *cfam_attr_groups[] = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  894) 	&cfam_attr_group,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  895) 	NULL,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  896) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  897) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  898) static char *cfam_devnode(struct device *dev, umode_t *mode,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  899) 			  kuid_t *uid, kgid_t *gid)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  900) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  901) 	struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  902) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  903) #ifdef CONFIG_FSI_NEW_DEV_NODE
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  904) 	return kasprintf(GFP_KERNEL, "fsi/cfam%d", slave->cdev_idx);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  905) #else
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  906) 	return kasprintf(GFP_KERNEL, "cfam%d", slave->cdev_idx);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  907) #endif
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  908) }
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  909) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  910) static const struct device_type cfam_type = {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  911) 	.name = "cfam",
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  912) 	.devnode = cfam_devnode,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  913) 	.groups = cfam_attr_groups
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  914) };
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  915) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  916) static char *fsi_cdev_devnode(struct device *dev, umode_t *mode,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  917) 			      kuid_t *uid, kgid_t *gid)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  918) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  919) #ifdef CONFIG_FSI_NEW_DEV_NODE
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  920) 	return kasprintf(GFP_KERNEL, "fsi/%s", dev_name(dev));
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  921) #else
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  922) 	return kasprintf(GFP_KERNEL, "%s", dev_name(dev));
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  923) #endif
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  924) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  925) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  926) const struct device_type fsi_cdev_type = {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  927) 	.name = "fsi-cdev",
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  928) 	.devnode = fsi_cdev_devnode,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  929) };
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  930) EXPORT_SYMBOL_GPL(fsi_cdev_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  931) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  932) /* Backward compatible /dev/ numbering in "old style" mode */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  933) static int fsi_adjust_index(int index)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  934) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  935) #ifdef CONFIG_FSI_NEW_DEV_NODE
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  936) 	return index;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  937) #else
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  938) 	return index + 1;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  939) #endif
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  940) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  941) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  942) static int __fsi_get_new_minor(struct fsi_slave *slave, enum fsi_dev_type type,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  943) 			       dev_t *out_dev, int *out_index)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  944) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  945) 	int cid = slave->chip_id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  946) 	int id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  947) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  948) 	/* Check if we qualify for legacy numbering */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  949) 	if (cid >= 0 && cid < 16 && type < 4) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  950) 		/* Try reserving the legacy number */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  951) 		id = (cid << 4) | type;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  952) 		id = ida_simple_get(&fsi_minor_ida, id, id + 1, GFP_KERNEL);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  953) 		if (id >= 0) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  954) 			*out_index = fsi_adjust_index(cid);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  955) 			*out_dev = fsi_base_dev + id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  956) 			return 0;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  957) 		}
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  958) 		/* Other failure */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  959) 		if (id != -ENOSPC)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  960) 			return id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  961) 		/* Fallback to non-legacy allocation */
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  962) 	}
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  963) 	id = ida_simple_get(&fsi_minor_ida, FSI_CHAR_LEGACY_TOP,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  964) 			    FSI_CHAR_MAX_DEVICES, GFP_KERNEL);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  965) 	if (id < 0)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  966) 		return id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  967) 	*out_index = fsi_adjust_index(id);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  968) 	*out_dev = fsi_base_dev + id;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  969) 	return 0;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  970) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  971) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  972) int fsi_get_new_minor(struct fsi_device *fdev, enum fsi_dev_type type,
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  973) 		      dev_t *out_dev, int *out_index)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  974) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  975) 	return __fsi_get_new_minor(fdev->slave, type, out_dev, out_index);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  976) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  977) EXPORT_SYMBOL_GPL(fsi_get_new_minor);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  978) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  979) void fsi_free_minor(dev_t dev)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  980) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  981) 	ida_simple_remove(&fsi_minor_ida, MINOR(dev));
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  982) }
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  983) EXPORT_SYMBOL_GPL(fsi_free_minor);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000  984) 
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500  985) static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id)
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500  986) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000  987) 	uint32_t cfam_id;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  988) 	struct fsi_slave *slave;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  989) 	uint8_t crc;
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500  990) 	__be32 data, llmode, slbus;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  991) 	int rc;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  992) 
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  993) 	/* Currently, we only support single slaves on a link, and use the
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  994) 	 * full 23-bit address range
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  995) 	 */
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  996) 	if (id != 0)
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  997) 		return -EINVAL;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500  998) 
11454d6dc8181 (Joel Stanley           2018-06-18 13:13:35 +0930  999) 	rc = fsi_master_read(master, link, id, 0, &data, sizeof(data));
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1000) 	if (rc) {
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1001) 		dev_dbg(&master->dev, "can't read slave %02x:%02x %d\n",
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1002) 				link, id, rc);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1003) 		return -ENODEV;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1004) 	}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1005) 	cfam_id = be32_to_cpu(data);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1006) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1007) 	crc = crc4(0, cfam_id, 32);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1008) 	if (crc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1009) 		dev_warn(&master->dev, "slave %02x:%02x invalid cfam id CRC!\n",
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1010) 				link, id);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1011) 		return -EIO;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1012) 	}
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1013) 
638bd9ac847e8 (Christopher Bostic     2018-02-12 15:45:46 +1030 1014) 	dev_dbg(&master->dev, "fsi: found chip %08x at %02x:%02x:%02x\n",
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1015) 			cfam_id, master->idx, link, id);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1016) 
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1017) 	/* If we're behind a master that doesn't provide a self-running bus
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1018) 	 * clock, put the slave into async mode
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1019) 	 */
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1020) 	if (master->flags & FSI_MASTER_FLAG_SWCLOCK) {
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1021) 		llmode = cpu_to_be32(FSI_LLMODE_ASYNC);
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1022) 		rc = fsi_master_write(master, link, id,
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1023) 				FSI_SLAVE_BASE + FSI_LLMODE,
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1024) 				&llmode, sizeof(llmode));
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1025) 		if (rc)
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1026) 			dev_warn(&master->dev,
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1027) 				"can't set llmode on slave:%02x:%02x %d\n",
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1028) 				link, id, rc);
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1029) 	}
4af889b0ff78a (Jeremy Kerr            2017-06-06 16:08:58 -0500 1030) 
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1031) 	/* We can communicate with a slave; create the slave device and
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1032) 	 * register.
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1033) 	 */
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1034) 	slave = kzalloc(sizeof(*slave), GFP_KERNEL);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1035) 	if (!slave)
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1036) 		return -ENOMEM;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1037) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1038) 	dev_set_name(&slave->dev, "slave@%02x:%02x", link, id);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1039) 	slave->dev.type = &cfam_type;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1040) 	slave->dev.parent = &master->dev;
f6a2f8eb73f0d (Jeremy Kerr            2018-02-12 15:45:45 +1030 1041) 	slave->dev.of_node = fsi_slave_find_of_node(master, link, id);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1042) 	slave->dev.release = fsi_slave_release;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1043) 	device_initialize(&slave->dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1044) 	slave->cfam_id = cfam_id;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1045) 	slave->master = master;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1046) 	slave->link = link;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1047) 	slave->id = id;
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1048) 	slave->size = FSI_SLAVE_SIZE_23b;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1049) 	slave->t_send_delay = 16;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1050) 	slave->t_echo_delay = 16;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1051) 
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1052) 	/* Get chip ID if any */
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1053) 	slave->chip_id = -1;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1054) 	if (slave->dev.of_node) {
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1055) 		uint32_t prop;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1056) 		if (!of_property_read_u32(slave->dev.of_node, "chip-id", &prop))
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1057) 			slave->chip_id = prop;
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1058) 
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1059) 	}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1060) 
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1061) 	slbus = cpu_to_be32(FSI_SLBUS_FORCE);
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1062) 	rc = fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SLBUS,
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1063) 			      &slbus, sizeof(slbus));
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1064) 	if (rc)
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1065) 		dev_warn(&master->dev,
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1066) 			 "can't set slbus on slave:%02x:%02x %d\n", link, id,
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1067) 			 rc);
196964a31cf8c (Eddie James            2020-05-20 13:17:07 -0500 1068) 
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1069) 	rc = fsi_slave_set_smode(slave);
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1070) 	if (rc) {
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1071) 		dev_warn(&master->dev,
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1072) 				"can't set smode on slave:%02x:%02x %d\n",
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1073) 				link, id, rc);
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1074) 		goto err_free;
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1075) 	}
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1076) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1077) 	/* Allocate a minor in the FSI space */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1078) 	rc = __fsi_get_new_minor(slave, fsi_dev_cfam, &slave->dev.devt,
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1079) 				 &slave->cdev_idx);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1080) 	if (rc)
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1081) 		goto err_free;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1082) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1083) 	/* Create chardev for userspace access */
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1084) 	cdev_init(&slave->cdev, &cfam_fops);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1085) 	rc = cdev_device_add(&slave->cdev, &slave->dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1086) 	if (rc) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1087) 		dev_err(&slave->dev, "Error %d creating slave device\n", rc);
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1088) 		goto err_free_ida;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1089) 	}
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1090) 
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1091) 	/* Now that we have the cdev registered with the core, any fatal
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1092) 	 * failures beyond this point will need to clean up through
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1093) 	 * cdev_device_del(). Fortunately though, nothing past here is fatal.
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1094) 	 */
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1095) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1096) 	if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1097) 		master->link_config(master, link,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1098) 				    slave->t_send_delay,
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1099) 				    slave->t_echo_delay);
2b545cd8e1b2a (Jeremy Kerr            2017-06-06 16:08:42 -0500 1100) 
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1101) 	/* Legacy raw file -> to be removed */
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1102) 	rc = device_create_bin_file(&slave->dev, &fsi_slave_raw_attr);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1103) 	if (rc)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1104) 		dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1105) 
0a213777d1dd8 (Benjamin Herrenschmidt 2018-06-20 15:16:31 +1000 1106) 
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500 1107) 	rc = fsi_slave_scan(slave);
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500 1108) 	if (rc)
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500 1109) 		dev_dbg(&master->dev, "failed during slave scan with: %d\n",
f7ade2a603cfd (Jeremy Kerr            2017-06-06 16:08:44 -0500 1110) 				rc);
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1111) 
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1112) 	return 0;
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1113) 
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1114) err_free_ida:
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1115) 	fsi_free_minor(slave->dev.devt);
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1116) err_free:
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1117) 	of_node_put(slave->dev.of_node);
371975b0b0752 (Jeremy Kerr            2019-06-28 16:07:37 +0800 1118) 	kfree(slave);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1119) 	return rc;
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1120) }
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1121) 
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1122) /* FSI master support */
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1123) static int fsi_check_access(uint32_t addr, size_t size)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1124) {
99f039e97bf8a (Eddie James            2018-02-12 15:45:43 +1030 1125) 	if (size == 4) {
99f039e97bf8a (Eddie James            2018-02-12 15:45:43 +1030 1126) 		if (addr & 0x3)
99f039e97bf8a (Eddie James            2018-02-12 15:45:43 +1030 1127) 			return -EINVAL;
99f039e97bf8a (Eddie James            2018-02-12 15:45:43 +1030 1128) 	} else if (size == 2) {
99f039e97bf8a (Eddie James            2018-02-12 15:45:43 +1030 1129) 		if (addr & 0x1)
99f039e97bf8a (Eddie James            2018-02-12 15:45:43 +1030 1130) 			return -EINVAL;
99f039e97bf8a (Eddie James            2018-02-12 15:45:43 +1030 1131) 	} else if (size != 1)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1132) 		return -EINVAL;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1133) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1134) 	return 0;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1135) }
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1136) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1137) static int fsi_master_read(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1138) 		uint8_t slave_id, uint32_t addr, void *val, size_t size)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1139) {
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1140) 	int rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1141) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1142) 	trace_fsi_master_read(master, link, slave_id, addr, size);
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1143) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1144) 	rc = fsi_check_access(addr, size);
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1145) 	if (!rc)
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1146) 		rc = master->read(master, link, slave_id, addr, val, size);
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1147) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1148) 	trace_fsi_master_rw_result(master, link, slave_id, addr, size,
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1149) 			false, val, rc);
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1150) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1151) 	return rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1152) }
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1153) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1154) static int fsi_master_write(struct fsi_master *master, int link,
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1155) 		uint8_t slave_id, uint32_t addr, const void *val, size_t size)
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1156) {
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1157) 	int rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1158) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1159) 	trace_fsi_master_write(master, link, slave_id, addr, size, val);
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1160) 
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1161) 	rc = fsi_check_access(addr, size);
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1162) 	if (!rc)
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1163) 		rc = master->write(master, link, slave_id, addr, val, size);
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1164) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1165) 	trace_fsi_master_rw_result(master, link, slave_id, addr, size,
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1166) 			true, val, rc);
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1167) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1168) 	return rc;
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1169) }
014c2abc530d7 (Jeremy Kerr            2017-06-06 16:08:40 -0500 1170) 
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1171) static int fsi_master_link_disable(struct fsi_master *master, int link)
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1172) {
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1173) 	if (master->link_enable)
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1174) 		return master->link_enable(master, link, false);
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1175) 
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1176) 	return 0;
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1177) }
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1178) 
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1179) static int fsi_master_link_enable(struct fsi_master *master, int link)
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1180) {
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1181) 	if (master->link_enable)
04635a30dd538 (Eddie James            2020-06-09 16:39:27 -0500 1182) 		return master->link_enable(master, link, true);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1183) 
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1184) 	return 0;
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1185) }
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1186) 
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1187) /*
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1188)  * Issue a break command on this link
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1189)  */
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1190) static int fsi_master_break(struct fsi_master *master, int link)
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1191) {
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1192) 	int rc = 0;
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1193) 
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1194) 	trace_fsi_master_break(master, link);
66433b05a3b2b (Jeremy Kerr            2017-06-06 16:08:51 -0500 1195) 
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1196) 	if (master->send_break)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1197) 		rc = master->send_break(master, link);
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1198) 	if (master->link_config)
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1199) 		master->link_config(master, link, 16, 16);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1200) 
a2e7da86cc392 (Benjamin Herrenschmidt 2018-05-29 15:01:07 +1000 1201) 	return rc;
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1202) }
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1203) 
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1204) static int fsi_master_scan(struct fsi_master *master)
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1205) {
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1206) 	int link, rc;
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1207) 
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1208) 	for (link = 0; link < master->n_links; link++) {
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1209) 		rc = fsi_master_link_enable(master, link);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1210) 		if (rc) {
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1211) 			dev_dbg(&master->dev,
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1212) 				"enable link %d failed: %d\n", link, rc);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1213) 			continue;
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1214) 		}
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1215) 		rc = fsi_master_break(master, link);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1216) 		if (rc) {
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1217) 			fsi_master_link_disable(master, link);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1218) 			dev_dbg(&master->dev,
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1219) 				"break to link %d failed: %d\n", link, rc);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1220) 			continue;
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1221) 		}
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1222) 
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1223) 		rc = fsi_slave_init(master, link, 0);
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1224) 		if (rc)
b36875a453ef8 (Eddie James            2020-06-09 16:39:28 -0500 1225) 			fsi_master_link_disable(master, link);
26095282119ec (Christopher Bostic     2017-06-06 16:08:41 -0500 1226) 	}
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1227) 
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1228) 	return 0;
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1229) }
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1230) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1231) static int fsi_slave_remove_device(struct device *dev, void *arg)
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1232) {
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1233) 	device_unregister(dev);
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1234) 	return 0;
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1235) }
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1236) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1237) static int fsi_master_remove_slave(struct device *dev, void *arg)
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1238) {
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1239) 	struct fsi_slave *slave = to_fsi_slave(dev);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1240) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1241) 	device_for_each_child(dev, NULL, fsi_slave_remove_device);
d1dcd67825760 (Benjamin Herrenschmidt 2018-06-21 12:34:22 +1000 1242) 	cdev_device_del(&slave->cdev, &slave->dev);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1243) 	put_device(dev);
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1244) 	return 0;
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1245) }
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1246) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1247) static void fsi_master_unscan(struct fsi_master *master)
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1248) {
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1249) 	device_for_each_child(&master->dev, NULL, fsi_master_remove_slave);
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1250) }
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1251) 
15362d69c4c88 (Jeremy Kerr            2018-02-12 15:45:40 +1030 1252) int fsi_master_rescan(struct fsi_master *master)
15362d69c4c88 (Jeremy Kerr            2018-02-12 15:45:40 +1030 1253) {
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1254) 	int rc;
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1255) 
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1256) 	mutex_lock(&master->scan_lock);
15362d69c4c88 (Jeremy Kerr            2018-02-12 15:45:40 +1030 1257) 	fsi_master_unscan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1258) 	rc = fsi_master_scan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1259) 	mutex_unlock(&master->scan_lock);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1260) 
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1261) 	return rc;
15362d69c4c88 (Jeremy Kerr            2018-02-12 15:45:40 +1030 1262) }
15362d69c4c88 (Jeremy Kerr            2018-02-12 15:45:40 +1030 1263) EXPORT_SYMBOL_GPL(fsi_master_rescan);
15362d69c4c88 (Jeremy Kerr            2018-02-12 15:45:40 +1030 1264) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1265) static ssize_t master_rescan_store(struct device *dev,
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1266) 		struct device_attribute *attr, const char *buf, size_t count)
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1267) {
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1268) 	struct fsi_master *master = to_fsi_master(dev);
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1269) 	int rc;
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1270) 
15362d69c4c88 (Jeremy Kerr            2018-02-12 15:45:40 +1030 1271) 	rc = fsi_master_rescan(master);
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1272) 	if (rc < 0)
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1273) 		return rc;
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1274) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1275) 	return count;
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1276) }
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1277) 
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1278) static DEVICE_ATTR(rescan, 0200, NULL, master_rescan_store);
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1279) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1280) static ssize_t master_break_store(struct device *dev,
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1281) 		struct device_attribute *attr, const char *buf, size_t count)
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1282) {
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1283) 	struct fsi_master *master = to_fsi_master(dev);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1284) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1285) 	fsi_master_break(master, 0);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1286) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1287) 	return count;
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1288) }
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1289) 
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1290) static DEVICE_ATTR(break, 0200, NULL, master_break_store);
125739cbc1c3b (Jeremy Kerr            2017-06-06 16:08:49 -0500 1291) 
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1292) static struct attribute *master_attrs[] = {
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1293) 	&dev_attr_break.attr,
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1294) 	&dev_attr_rescan.attr,
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1295) 	NULL
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1296) };
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1297) 
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1298) ATTRIBUTE_GROUPS(master);
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1299) 
56ec311fddacd (kbuild test robot      2019-11-08 15:49:40 +1030 1300) static struct class fsi_master_class = {
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1301) 	.name = "fsi-master",
cf700ba035dce (Jeremy Kerr            2019-11-08 15:49:36 +1030 1302) 	.dev_groups = master_groups,
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1303) };
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1304) 
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1305) int fsi_master_register(struct fsi_master *master)
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1306) {
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1307) 	int rc;
f3aa2c6f98e53 (Christopher Bostic     2018-02-12 15:45:49 +1030 1308) 	struct device_node *np;
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1309) 
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1310) 	mutex_init(&master->scan_lock);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1311) 	master->idx = ida_simple_get(&master_ida, 0, INT_MAX, GFP_KERNEL);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1312) 	dev_set_name(&master->dev, "fsi%d", master->idx);
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1313) 	master->dev.class = &fsi_master_class;
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1314) 
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1315) 	rc = device_register(&master->dev);
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1316) 	if (rc) {
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1317) 		ida_simple_remove(&master_ida, master->idx);
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1318) 		return rc;
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1319) 	}
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1320) 
f3aa2c6f98e53 (Christopher Bostic     2018-02-12 15:45:49 +1030 1321) 	np = dev_of_node(&master->dev);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1322) 	if (!of_property_read_bool(np, "no-scan-on-init")) {
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1323) 		mutex_lock(&master->scan_lock);
f3aa2c6f98e53 (Christopher Bostic     2018-02-12 15:45:49 +1030 1324) 		fsi_master_scan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1325) 		mutex_unlock(&master->scan_lock);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1326) 	}
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1327) 
414c1026319bc (Jeremy Kerr            2017-06-06 16:08:38 -0500 1328) 	return 0;
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1329) }
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1330) EXPORT_SYMBOL_GPL(fsi_master_register);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1331) 
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1332) void fsi_master_unregister(struct fsi_master *master)
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1333) {
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1334) 	if (master->idx >= 0) {
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1335) 		ida_simple_remove(&master_ida, master->idx);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1336) 		master->idx = -1;
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1337) 	}
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1338) 
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1339) 	mutex_lock(&master->scan_lock);
cd0fdb5c07b27 (Christopher Bostic     2017-06-06 16:08:46 -0500 1340) 	fsi_master_unscan(master);
9840fcd8cc43b (Benjamin Herrenschmidt 2018-06-21 18:00:05 +1000 1341) 	mutex_unlock(&master->scan_lock);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1342) 	device_unregister(&master->dev);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1343) }
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1344) EXPORT_SYMBOL_GPL(fsi_master_unregister);
09aecfab93b8f (Jeremy Kerr            2017-06-06 16:08:36 -0500 1345) 
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1346) /* FSI core & Linux bus type definitions */
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1347) 
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1348) static int fsi_bus_match(struct device *dev, struct device_driver *drv)
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1349) {
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1350) 	struct fsi_device *fsi_dev = to_fsi_dev(dev);
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1351) 	struct fsi_driver *fsi_drv = to_fsi_drv(drv);
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1352) 	const struct fsi_device_id *id;
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1353) 
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1354) 	if (!fsi_drv->id_table)
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1355) 		return 0;
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1356) 
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1357) 	for (id = fsi_drv->id_table; id->engine_type; id++) {
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1358) 		if (id->engine_type != fsi_dev->engine_type)
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1359) 			continue;
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1360) 		if (id->version == FSI_VERSION_ANY ||
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1361) 				id->version == fsi_dev->version)
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1362) 			return 1;
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1363) 	}
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1364) 
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1365) 	return 0;
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1366) }
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1367) 
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1368) int fsi_driver_register(struct fsi_driver *fsi_drv)
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1369) {
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1370) 	if (!fsi_drv)
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1371) 		return -EINVAL;
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1372) 	if (!fsi_drv->id_table)
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1373) 		return -EINVAL;
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1374) 
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1375) 	return driver_register(&fsi_drv->drv);
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1376) }
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1377) EXPORT_SYMBOL_GPL(fsi_driver_register);
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1378) 
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1379) void fsi_driver_unregister(struct fsi_driver *fsi_drv)
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1380) {
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1381) 	driver_unregister(&fsi_drv->drv);
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1382) }
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1383) EXPORT_SYMBOL_GPL(fsi_driver_unregister);
356d8009a5a45 (Christopher Bostic     2017-06-06 16:08:48 -0500 1384) 
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1385) struct bus_type fsi_bus_type = {
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1386) 	.name		= "fsi",
dd37eed7db0f7 (Jeremy Kerr            2017-02-01 10:53:43 -0600 1387) 	.match		= fsi_bus_match,
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1388) };
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1389) EXPORT_SYMBOL_GPL(fsi_bus_type);
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1390) 
496f8931b6460 (Joel Stanley           2017-07-11 17:00:39 +0930 1391) static int __init fsi_init(void)
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1392) {
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1393) 	int rc;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1394) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1395) 	rc = alloc_chrdev_region(&fsi_base_dev, 0, FSI_CHAR_MAX_DEVICES, "fsi");
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1396) 	if (rc)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1397) 		return rc;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1398) 	rc = bus_register(&fsi_bus_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1399) 	if (rc)
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1400) 		goto fail_bus;
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1401) 
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1402) 	rc = class_register(&fsi_master_class);
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1403) 	if (rc)
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1404) 		goto fail_class;
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1405) 
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1406) 	return 0;
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1407) 
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1408)  fail_class:
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1409) 	bus_unregister(&fsi_bus_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1410)  fail_bus:
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1411) 	unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1412) 	return rc;
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1413) }
496f8931b6460 (Joel Stanley           2017-07-11 17:00:39 +0930 1414) postcore_initcall(fsi_init);
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1415) 
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1416) static void fsi_exit(void)
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1417) {
2e32c2d675ac1 (Jeremy Kerr            2019-11-08 15:49:35 +1030 1418) 	class_unregister(&fsi_master_class);
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1419) 	bus_unregister(&fsi_bus_type);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1420) 	unregister_chrdev_region(fsi_base_dev, FSI_CHAR_MAX_DEVICES);
0ab5fe5374743 (Benjamin Herrenschmidt 2018-06-20 15:22:52 +1000 1421) 	ida_destroy(&fsi_minor_ida);
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1422) }
0508ad1fff11a (Jeremy Kerr            2017-02-01 10:53:41 -0600 1423) module_exit(fsi_exit);
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500 1424) module_param(discard_errors, int, 0664);
acb7e8f7448ef (Christopher Bostic     2017-06-06 16:08:59 -0500 1425) MODULE_LICENSE("GPL");
1fa847d74a75b (Jeremy Kerr            2017-06-06 16:08:52 -0500 1426) MODULE_PARM_DESC(discard_errors, "Don't invoke error handling on bus accesses");