From 8a1939829f9cf4ec2354afeaf592735b6eb77ab9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 3 Jun 2020 13:05:26 +0100 Subject: fsi: master-ast-cf: fix spelling mistake "firwmare" -> "firmware" There is a spelling mistake in a dev_err error message. Fix it. Signed-off-by: Colin Ian King Reviewed-by: Andrew Jeffery Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-ast-cf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-master-ast-cf.c b/drivers/fsi/fsi-master-ast-cf.c index 04d10ea8d343..85d9be38b32b 100644 --- a/drivers/fsi/fsi-master-ast-cf.c +++ b/drivers/fsi/fsi-master-ast-cf.c @@ -838,7 +838,7 @@ static int load_copro_firmware(struct fsi_master_acf *master) rc = request_firmware(&fw, FW_FILE_NAME, master->dev); if (rc) { dev_err( - master->dev, "Error %d to load firwmare '%s' !\n", + master->dev, "Error %d to load firmware '%s' !\n", rc, FW_FILE_NAME); return rc; } -- cgit v1.2.3 From 6e0ef7d2cee1abf8a8ff4862f528067c58b3bcc1 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Thu, 9 Jul 2020 14:17:43 -0500 Subject: fsi: aspeed: Enable 23-bit addressing In order to access more than the second hub link, 23-bit addressing is required. The core provides the highest two bits of address as the slave ID to the master. Signed-off-by: Eddie James Acked-by: Jeremy Kerr Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-aspeed.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index f49742b310c2..b49dccf14315 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -241,9 +241,10 @@ static int aspeed_master_read(struct fsi_master *master, int link, struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); int ret; - if (id != 0) + if (id > 0x3) return -EINVAL; + addr |= id << 21; addr += link * FSI_HUB_LINK_SIZE; switch (size) { @@ -273,9 +274,10 @@ static int aspeed_master_write(struct fsi_master *master, int link, struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); int ret; - if (id != 0) + if (id > 0x3) return -EINVAL; + addr |= id << 21; addr += link * FSI_HUB_LINK_SIZE; switch (size) { -- cgit v1.2.3 From 3c3c484850bcb4b28f2377e3d641a32c42af949c Mon Sep 17 00:00:00 2001 From: Xu Wang Date: Mon, 13 Jul 2020 03:33:13 +0000 Subject: fsi: fsi-occ: fix return value check in occ_probe() In case of error, the function platform_device_register_full() returns ERR_PTR() and never returns NULL. The NULL test in the return value check should be replaced with IS_ERR(). Signed-off-by: Xu Wang Reviewed-by: Guenter Roeck Signed-off-by: Joel Stanley --- drivers/fsi/fsi-occ.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index 7da9c81759ac..9eeb856c8905 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -555,7 +555,7 @@ static int occ_probe(struct platform_device *pdev) hwmon_dev_info.id = occ->idx; hwmon_dev = platform_device_register_full(&hwmon_dev_info); - if (!hwmon_dev) + if (IS_ERR(hwmon_dev)) dev_warn(dev, "failed to create hwmon device\n"); return 0; -- cgit v1.2.3 From 04635a30dd53890fac4e926f91c4ec8619c9227b Mon Sep 17 00:00:00 2001 From: Eddie James Date: Tue, 9 Jun 2020 16:39:27 -0500 Subject: fsi: master: Add boolean parameter to link_enable function Add the ability to disable a link with a boolean parameter to the link_enable function. This is necessary so that the master can disable links that it isn't using; for example, links to slaves that fail initialization. Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/fsi/fsi-core.c | 2 +- drivers/fsi/fsi-master-aspeed.c | 7 ++++++- drivers/fsi/fsi-master-ast-cf.c | 5 +++-- drivers/fsi/fsi-master-gpio.c | 5 +++-- drivers/fsi/fsi-master-hub.c | 7 ++++++- drivers/fsi/fsi-master.h | 3 ++- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c index 8244da8a7241..0743bba42757 100644 --- a/drivers/fsi/fsi-core.c +++ b/drivers/fsi/fsi-core.c @@ -1157,7 +1157,7 @@ static int fsi_master_write(struct fsi_master *master, int link, static int fsi_master_link_enable(struct fsi_master *master, int link) { if (master->link_enable) - return master->link_enable(master, link); + return master->link_enable(master, link, true); return 0; } diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index b49dccf14315..6152cfe6d18e 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -301,7 +301,8 @@ static int aspeed_master_write(struct fsi_master *master, int link, return 0; } -static int aspeed_master_link_enable(struct fsi_master *master, int link) +static int aspeed_master_link_enable(struct fsi_master *master, int link, + bool enable) { struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); int idx, bit, ret; @@ -312,6 +313,10 @@ static int aspeed_master_link_enable(struct fsi_master *master, int link) reg = cpu_to_be32(0x80000000 >> bit); + if (!enable) + return opb_writel(aspeed, ctrl_base + FSI_MCENP0 + (4 * idx), + reg); + ret = opb_writel(aspeed, ctrl_base + FSI_MSENP0 + (4 * idx), reg); if (ret) return ret; diff --git a/drivers/fsi/fsi-master-ast-cf.c b/drivers/fsi/fsi-master-ast-cf.c index 85d9be38b32b..57a779a89b07 100644 --- a/drivers/fsi/fsi-master-ast-cf.c +++ b/drivers/fsi/fsi-master-ast-cf.c @@ -1039,7 +1039,8 @@ static void fsi_master_acf_setup_external(struct fsi_master_acf *master) gpiod_direction_input(master->gpio_data); } -static int fsi_master_acf_link_enable(struct fsi_master *_master, int link) +static int fsi_master_acf_link_enable(struct fsi_master *_master, int link, + bool enable) { struct fsi_master_acf *master = to_fsi_master_acf(_master); int rc = -EBUSY; @@ -1049,7 +1050,7 @@ static int fsi_master_acf_link_enable(struct fsi_master *_master, int link) mutex_lock(&master->lock); if (!master->external_mode) { - gpiod_set_value(master->gpio_enable, 1); + gpiod_set_value(master->gpio_enable, enable ? 1 : 0); rc = 0; } mutex_unlock(&master->lock); diff --git a/drivers/fsi/fsi-master-gpio.c b/drivers/fsi/fsi-master-gpio.c index 4dcce17f243f..aa97c4a250cb 100644 --- a/drivers/fsi/fsi-master-gpio.c +++ b/drivers/fsi/fsi-master-gpio.c @@ -678,7 +678,8 @@ static void fsi_master_gpio_init_external(struct fsi_master_gpio *master) gpiod_direction_input(master->gpio_data); } -static int fsi_master_gpio_link_enable(struct fsi_master *_master, int link) +static int fsi_master_gpio_link_enable(struct fsi_master *_master, int link, + bool enable) { struct fsi_master_gpio *master = to_fsi_master_gpio(_master); int rc = -EBUSY; @@ -688,7 +689,7 @@ static int fsi_master_gpio_link_enable(struct fsi_master *_master, int link) mutex_lock(&master->cmd_lock); if (!master->external_mode) { - gpiod_set_value(master->gpio_enable, 1); + gpiod_set_value(master->gpio_enable, enable ? 1 : 0); rc = 0; } mutex_unlock(&master->cmd_lock); diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c index def35cf92571..1d3cf2da6a16 100644 --- a/drivers/fsi/fsi-master-hub.c +++ b/drivers/fsi/fsi-master-hub.c @@ -77,7 +77,8 @@ static int hub_master_break(struct fsi_master *master, int link) return hub_master_write(master, link, 0, addr, &cmd, sizeof(cmd)); } -static int hub_master_link_enable(struct fsi_master *master, int link) +static int hub_master_link_enable(struct fsi_master *master, int link, + bool enable) { struct fsi_master_hub *hub = to_fsi_master_hub(master); int idx, bit; @@ -89,6 +90,10 @@ static int hub_master_link_enable(struct fsi_master *master, int link) reg = cpu_to_be32(0x80000000 >> bit); + if (!enable) + return fsi_device_write(hub->upstream, FSI_MCENP0 + (4 * idx), + ®, 4); + rc = fsi_device_write(hub->upstream, FSI_MSENP0 + (4 * idx), ®, 4); mdelay(FSI_LINK_ENABLE_SETUP_TIME); diff --git a/drivers/fsi/fsi-master.h b/drivers/fsi/fsi-master.h index 6e8d4d4d5149..cd6bee5e12a7 100644 --- a/drivers/fsi/fsi-master.h +++ b/drivers/fsi/fsi-master.h @@ -130,7 +130,8 @@ struct fsi_master { uint32_t addr, const void *val, size_t size); int (*term)(struct fsi_master *, int link, uint8_t id); int (*send_break)(struct fsi_master *, int link); - int (*link_enable)(struct fsi_master *, int link); + int (*link_enable)(struct fsi_master *, int link, + bool enable); int (*link_config)(struct fsi_master *, int link, u8 t_send_delay, u8 t_echo_delay); }; -- cgit v1.2.3 From b36875a453ef8cb429f5e1064a7329b751fd0dda Mon Sep 17 00:00:00 2001 From: Eddie James Date: Tue, 9 Jun 2020 16:39:28 -0500 Subject: fsi: core: Disable link when slave init fails In the case that links don't have slaves or fail to be accessed, the master should disable the link during the scan since it won't be using the slave. Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/fsi/fsi-core.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c index 0743bba42757..c9c3842f6e62 100644 --- a/drivers/fsi/fsi-core.c +++ b/drivers/fsi/fsi-core.c @@ -1154,6 +1154,14 @@ static int fsi_master_write(struct fsi_master *master, int link, return rc; } +static int fsi_master_link_disable(struct fsi_master *master, int link) +{ + if (master->link_enable) + return master->link_enable(master, link, false); + + return 0; +} + static int fsi_master_link_enable(struct fsi_master *master, int link) { if (master->link_enable) @@ -1192,12 +1200,15 @@ static int fsi_master_scan(struct fsi_master *master) } rc = fsi_master_break(master, link); if (rc) { + fsi_master_link_disable(master, link); dev_dbg(&master->dev, "break to link %d failed: %d\n", link, rc); continue; } - fsi_slave_init(master, link, 0); + rc = fsi_slave_init(master, link, 0); + if (rc) + fsi_master_link_disable(master, link); } return 0; -- cgit v1.2.3 From 196964a31cf8c4175fab28942071215e34f0a684 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Wed, 20 May 2020 13:17:07 -0500 Subject: fsi: core: Set slave local bus ownership during init The driver ought to claim local bus ownership of the slave it's communicating with. This is for multi-master setups. The slave (in theory) will deny access to masters who try to access the CFAM address space but who don't "own" the bus. As driver doesn't seem to perform any other teardown there is no need to "un-claim" ownership at teardown. Also I'm not aware of any multi-master setup using this driver so it shouldn't actually matter. Also, the hardware doesn't seem to enforce this despite being required in the specification... Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/fsi/fsi-core.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c index c9c3842f6e62..4e60e84cd17a 100644 --- a/drivers/fsi/fsi-core.c +++ b/drivers/fsi/fsi-core.c @@ -50,6 +50,7 @@ static const int engine_page_size = 0x400; #define FSI_SMODE 0x0 /* R/W: Mode register */ #define FSI_SISC 0x8 /* R/W: Interrupt condition */ #define FSI_SSTAT 0x14 /* R : Slave status */ +#define FSI_SLBUS 0x30 /* W : LBUS Ownership */ #define FSI_LLMODE 0x100 /* R/W: Link layer mode register */ /* @@ -66,6 +67,11 @@ static const int engine_page_size = 0x400; #define FSI_SMODE_LBCRR_SHIFT 8 /* Clk ratio shift */ #define FSI_SMODE_LBCRR_MASK 0xf /* Clk ratio mask */ +/* + * SLBUS fields + */ +#define FSI_SLBUS_FORCE 0x80000000 /* Force LBUS ownership */ + /* * LLMODE fields */ @@ -981,7 +987,7 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id) uint32_t cfam_id; struct fsi_slave *slave; uint8_t crc; - __be32 data, llmode; + __be32 data, llmode, slbus; int rc; /* Currently, we only support single slaves on a link, and use the @@ -1052,6 +1058,14 @@ static int fsi_slave_init(struct fsi_master *master, int link, uint8_t id) } + slbus = cpu_to_be32(FSI_SLBUS_FORCE); + rc = fsi_master_write(master, link, id, FSI_SLAVE_BASE + FSI_SLBUS, + &slbus, sizeof(slbus)); + if (rc) + dev_warn(&master->dev, + "can't set slbus on slave:%02x:%02x %d\n", link, id, + rc); + rc = fsi_slave_set_smode(slave); if (rc) { dev_warn(&master->dev, -- cgit v1.2.3 From a1d5ce111aa2f8b9d5d4db3ed85b11e53251d676 Mon Sep 17 00:00:00 2001 From: Eddie James Date: Mon, 6 Apr 2020 14:19:36 -0500 Subject: fsi: master: Remove link enable read-back Both the Aspeed and hub masters read back the link enable register after enabling the link, but this is unnecessary, so remove it. Signed-off-by: Eddie James Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-aspeed.c | 11 +---------- drivers/fsi/fsi-master-hub.c | 6 +++--- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index 6152cfe6d18e..2b8ca72baeb5 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -306,7 +306,7 @@ static int aspeed_master_link_enable(struct fsi_master *master, int link, { struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master); int idx, bit, ret; - __be32 reg, result; + __be32 reg; idx = link / 32; bit = link % 32; @@ -323,15 +323,6 @@ static int aspeed_master_link_enable(struct fsi_master *master, int link, mdelay(FSI_LINK_ENABLE_SETUP_TIME); - ret = opb_readl(aspeed, ctrl_base + FSI_MENP0 + (4 * idx), &result); - if (ret) - return ret; - - if (result != reg) { - dev_err(aspeed->dev, "%s failed: %08x\n", __func__, result); - return -EIO; - } - return 0; } diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c index 1d3cf2da6a16..3caa2da7838c 100644 --- a/drivers/fsi/fsi-master-hub.c +++ b/drivers/fsi/fsi-master-hub.c @@ -95,12 +95,12 @@ static int hub_master_link_enable(struct fsi_master *master, int link, ®, 4); rc = fsi_device_write(hub->upstream, FSI_MSENP0 + (4 * idx), ®, 4); + if (rc) + return rc; mdelay(FSI_LINK_ENABLE_SETUP_TIME); - fsi_device_read(hub->upstream, FSI_MENP0 + (4 * idx), ®, 4); - - return rc; + return 0; } static void hub_master_release(struct device *dev) -- cgit v1.2.3 From 31901bb74f5618929ce94880691c8448765415ac Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Thu, 6 Aug 2020 01:26:22 +0200 Subject: fsi: master: Constify hub_master_ids The only usage of hub_master_ids is to assign its address to the id_table field in the fsi_driver struct, which is a const pointer, so make it const to allow the compiler to put it in read-only memory. Signed-off-by: Rikard Falkeborn Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-hub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-master-hub.c b/drivers/fsi/fsi-master-hub.c index 3caa2da7838c..01f0a796111e 100644 --- a/drivers/fsi/fsi-master-hub.c +++ b/drivers/fsi/fsi-master-hub.c @@ -276,7 +276,7 @@ static int hub_master_remove(struct device *dev) return 0; } -static struct fsi_device_id hub_master_ids[] = { +static const struct fsi_device_id hub_master_ids[] = { { .engine_type = FSI_ENGID_HUB_MASTER, .version = FSI_VERSION_ANY, -- cgit v1.2.3 From f458c38f40fa7f03135b25e33884abc5fd028714 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Thu, 6 Aug 2020 01:26:23 +0200 Subject: fsi: sbefifo: Constify sbefifo_ids The only usage of sbefifo_ids is to assign its address to the id_table field in the fsi_driver struct, which is a const pointer, so make it const to allow the compiler to put it in read-only memory Signed-off-by: Rikard Falkeborn Signed-off-by: Joel Stanley --- drivers/fsi/fsi-sbefifo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c index f54df9ebc8b3..bfd5e5da8020 100644 --- a/drivers/fsi/fsi-sbefifo.c +++ b/drivers/fsi/fsi-sbefifo.c @@ -1028,7 +1028,7 @@ static int sbefifo_remove(struct device *dev) return 0; } -static struct fsi_device_id sbefifo_ids[] = { +static const struct fsi_device_id sbefifo_ids[] = { { .engine_type = FSI_ENGID_SBE, .version = FSI_VERSION_ANY, -- cgit v1.2.3 From 59165631b7e9deca0b93b029a1112f4f8f3df736 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Thu, 6 Aug 2020 01:26:24 +0200 Subject: fsi: scom: Constify scom_ids The only usage of scom_ids is to assign its address to the id_table field in the fsi_driver struct, which is a const pointer, so make it const to allow the compiler to put it in read-only memory Signed-off-by: Rikard Falkeborn Signed-off-by: Joel Stanley --- drivers/fsi/fsi-scom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c index 004dc03ccf09..b45bfab7b7f5 100644 --- a/drivers/fsi/fsi-scom.c +++ b/drivers/fsi/fsi-scom.c @@ -627,7 +627,7 @@ static int scom_remove(struct device *dev) return 0; } -static struct fsi_device_id scom_ids[] = { +static const struct fsi_device_id scom_ids[] = { { .engine_type = FSI_ENGID_SCOM, .version = FSI_VERSION_ANY, -- cgit v1.2.3 From 4d4905f6cc5b6534e9a3b6a3c75bcee840a27751 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 28 Jul 2020 12:25:23 +0930 Subject: dt-bindings: fsi: Document gpios The FSI master has some associated GPIOs that may be present on some hardware configurations. Reviewed-by: Andrew Jeffery Link: https://lore.kernel.org/r/20200728025527.174503-2-joel@jms.id.au Signed-off-by: Joel Stanley --- Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt index b758f91914f7..9853fefff5d8 100644 --- a/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt +++ b/Documentation/devicetree/bindings/fsi/fsi-master-aspeed.txt @@ -12,6 +12,13 @@ Required properties: - pinctrl-0: phandle to pinctrl node - pinctrl-names: pinctrl state +Optional properties: + - cfam-reset-gpios: GPIO for CFAM reset + + - fsi-routing-gpios: GPIO for setting the FSI mux (internal or cabled) + - fsi-mux-gpios: GPIO for detecting the desired FSI mux state + + Examples: fsi-master { @@ -21,4 +28,9 @@ Examples: pinctrl-names = "default"; pinctrl-0 = <&pinctrl_fsi1_default>; clocks = <&syscon ASPEED_CLK_GATE_FSICLK>; + + fsi-routing-gpios = <&gpio0 ASPEED_GPIO(Q, 7) GPIO_ACTIVE_HIGH>; + fsi-mux-gpios = <&gpio0 ASPEED_GPIO(B, 0) GPIO_ACTIVE_HIGH>; + + cfam-reset-gpios = <&gpio0 ASPEED_GPIO(Q, 0) GPIO_ACTIVE_LOW>; }; -- cgit v1.2.3 From f369a29bdde9f14040e9f0cc4ac610cdb216e93c Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 28 Jul 2020 12:25:24 +0930 Subject: fsi: aspeed: Support cabled FSI Some FSI capable systems have internal FSI signals, and some have external cabled FSI. Software can detect which machine this is by reading a jumper GPIO, and also control which pins the signals are routed to through a mux GPIO. This attempts to find the GPIOs at probe time. If they are not present in the device tree the driver will not error and continue as before. The mux GPIO is owned by the FSI driver to ensure it is not modified at runtime. The routing jumper obtained as non-exclusive to allow other software to inspect it's state. Reviewed-by: Andrew Jeffery Link: https://lore.kernel.org/r/20200728025527.174503-3-joel@jms.id.au Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-aspeed.c | 46 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index 2b8ca72baeb5..c282de76e6e7 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -13,6 +13,7 @@ #include #include #include +#include #include "fsi-master.h" @@ -417,6 +418,45 @@ static int aspeed_master_init(struct fsi_master_aspeed *aspeed) return 0; } +static int tacoma_cabled_fsi_fixup(struct device *dev) +{ + struct gpio_desc *routing_gpio, *mux_gpio; + int gpio; + + /* + * The routing GPIO is a jumper indicating we should mux for the + * externally connected FSI cable. + */ + routing_gpio = devm_gpiod_get_optional(dev, "fsi-routing", + GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE); + if (IS_ERR(routing_gpio)) + return PTR_ERR(routing_gpio); + if (!routing_gpio) + return 0; + + mux_gpio = devm_gpiod_get_optional(dev, "fsi-mux", GPIOD_ASIS); + if (IS_ERR(mux_gpio)) + return PTR_ERR(mux_gpio); + if (!mux_gpio) + return 0; + + gpio = gpiod_get_value(routing_gpio); + if (gpio < 0) + return gpio; + + /* If the routing GPIO is high we should set the mux to low. */ + if (gpio) { + gpiod_direction_output(mux_gpio, 0); + dev_info(dev, "FSI configured for external cable\n"); + } else { + gpiod_direction_output(mux_gpio, 1); + } + + devm_gpiod_put(dev, routing_gpio); + + return 0; +} + static int fsi_master_aspeed_probe(struct platform_device *pdev) { struct fsi_master_aspeed *aspeed; @@ -424,6 +464,12 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) int rc, links, reg; __be32 raw; + rc = tacoma_cabled_fsi_fixup(&pdev->dev); + if (rc) { + dev_err(&pdev->dev, "Tacoma FSI cable fixup failed\n"); + return rc; + } + aspeed = devm_kzalloc(&pdev->dev, sizeof(*aspeed), GFP_KERNEL); if (!aspeed) return -ENOMEM; -- cgit v1.2.3 From 4a80c2017bd9136a139773ba980341ea7e71dafd Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 28 Jul 2020 12:25:25 +0930 Subject: fsi: aspeed: Run the bus at maximum speed Testing of Tacoma has shown that the ASPEED master can be run at maximum speed. The exception is when wired externally with a cable, in which case we use a divisor of two to ensure reliable operation. Reviewed-by: Eddie James Link: https://lore.kernel.org/r/20200728025527.174503-4-joel@jms.id.au Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-aspeed.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index c282de76e6e7..f503f64ab32b 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -83,7 +83,11 @@ static const u32 fsi_base = 0xa0000000; #define FSI_LINK_ENABLE_SETUP_TIME 10 /* in mS */ -#define DEFAULT_DIVISOR 14 +/* Run the bus at maximum speed by default */ +#define FSI_DIVISOR_DEFAULT 1 +#define FSI_DIVISOR_CABLED 2 +static u16 aspeed_fsi_divisor = FSI_DIVISOR_DEFAULT; + #define OPB_POLL_TIMEOUT 10000 static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr, @@ -385,9 +389,11 @@ static int aspeed_master_init(struct fsi_master_aspeed *aspeed) opb_writel(aspeed, ctrl_base + FSI_MECTRL, reg); reg = cpu_to_be32(FSI_MMODE_ECRC | FSI_MMODE_EPC | FSI_MMODE_RELA - | fsi_mmode_crs0(DEFAULT_DIVISOR) - | fsi_mmode_crs1(DEFAULT_DIVISOR) + | fsi_mmode_crs0(aspeed_fsi_divisor) + | fsi_mmode_crs1(aspeed_fsi_divisor) | FSI_MMODE_P8_TO_LSB); + dev_info(aspeed->dev, "mmode set to %08x (divisor %d)\n", + be32_to_cpu(reg), aspeed_fsi_divisor); opb_writel(aspeed, ctrl_base + FSI_MMODE, reg); reg = cpu_to_be32(0xffff0000); @@ -446,6 +452,11 @@ static int tacoma_cabled_fsi_fixup(struct device *dev) /* If the routing GPIO is high we should set the mux to low. */ if (gpio) { + /* + * Cable signal integrity means we should run the bus + * slightly slower + */ + aspeed_fsi_divisor = FSI_DIVISOR_CABLED; gpiod_direction_output(mux_gpio, 0); dev_info(dev, "FSI configured for external cable\n"); } else { -- cgit v1.2.3 From add6895188e49aa6b730d647ca896559370aa2be Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 28 Jul 2020 12:25:26 +0930 Subject: fsi: aspeed: Add module param for bus divisor For testing and hardware debugging a user may wish to override the divisor at runtime. By setting fsi_master_aspeed.bus_div=N, the divisor will be set to N, if 0 < N <= 0x3ff. This is a module parameter and not a device tree option as it will only need to be set when testing or debugging. Reviewed-by: Eddie James Link: https://lore.kernel.org/r/20200728025527.174503-5-joel@jms.id.au Signed-off-by: Joel Stanley --- drivers/fsi/fsi-master-aspeed.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index f503f64ab32b..2531e826ba8b 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -87,6 +87,7 @@ static const u32 fsi_base = 0xa0000000; #define FSI_DIVISOR_DEFAULT 1 #define FSI_DIVISOR_CABLED 2 static u16 aspeed_fsi_divisor = FSI_DIVISOR_DEFAULT; +module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0); #define OPB_POLL_TIMEOUT 10000 @@ -454,9 +455,12 @@ static int tacoma_cabled_fsi_fixup(struct device *dev) if (gpio) { /* * Cable signal integrity means we should run the bus - * slightly slower + * slightly slower. Do not override if a kernel param + * has already overridden. */ - aspeed_fsi_divisor = FSI_DIVISOR_CABLED; + if (aspeed_fsi_divisor == FSI_DIVISOR_DEFAULT) + aspeed_fsi_divisor = FSI_DIVISOR_CABLED; + gpiod_direction_output(mux_gpio, 0); dev_info(dev, "FSI configured for external cable\n"); } else { -- cgit v1.2.3 From 4a851d714eadeabd65c7e321a2e7830f77d945c4 Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Tue, 28 Jul 2020 12:25:27 +0930 Subject: fsi: aspeed: Support CFAM reset GPIO Systems have a line for restting the remote CFAM. This is not part of the FSI master, but is associated with it, so it makes sense to include it in the master driver. This exposes a sysfs interface to reset the cfam, abstracting away the direction and polarity of the GPIO, as well as the timing of the reset pulse. Userspace will be blocked until the reset pulse is finished. The reset is hard coded to be in the range of (900, 1000) us. It was observed with a scope to regularly be just over 1ms. If the device tree property is not preset the driver will silently continue. Reviewed-by: Andrew Jeffery Link: https://lore.kernel.org/r/20200728025527.174503-6-joel@jms.id.au Signed-off-by: Joel Stanley --- Documentation/ABI/testing/sysfs-bus-fsi | 8 ++++++ drivers/fsi/fsi-master-aspeed.c | 43 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-bus-fsi b/Documentation/ABI/testing/sysfs-bus-fsi index 320697bdf41d..d148214181a1 100644 --- a/Documentation/ABI/testing/sysfs-bus-fsi +++ b/Documentation/ABI/testing/sysfs-bus-fsi @@ -36,3 +36,11 @@ Contact: linux-fsi@lists.ozlabs.org Description: Provides a means of reading/writing a 32 bit value from/to a specified FSI bus address. + +What: /sys/bus/platform/devices/../cfam_reset +Date: Sept 2020 +KernelVersion: 5.10 +Contact: linux-fsi@lists.ozlabs.org +Description: + Provides a means of resetting the cfam that is attached to the + FSI device. diff --git a/drivers/fsi/fsi-master-aspeed.c b/drivers/fsi/fsi-master-aspeed.c index 2531e826ba8b..c006ec008a1a 100644 --- a/drivers/fsi/fsi-master-aspeed.c +++ b/drivers/fsi/fsi-master-aspeed.c @@ -22,6 +22,7 @@ struct fsi_master_aspeed { struct device *dev; void __iomem *base; struct clk *clk; + struct gpio_desc *cfam_reset_gpio; }; #define to_fsi_master_aspeed(m) \ @@ -425,6 +426,43 @@ static int aspeed_master_init(struct fsi_master_aspeed *aspeed) return 0; } +static ssize_t cfam_reset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsi_master_aspeed *aspeed = dev_get_drvdata(dev); + + gpiod_set_value(aspeed->cfam_reset_gpio, 1); + usleep_range(900, 1000); + gpiod_set_value(aspeed->cfam_reset_gpio, 0); + + return count; +} + +static DEVICE_ATTR(cfam_reset, 0200, NULL, cfam_reset_store); + +static int setup_cfam_reset(struct fsi_master_aspeed *aspeed) +{ + struct device *dev = aspeed->dev; + struct gpio_desc *gpio; + int rc; + + gpio = devm_gpiod_get_optional(dev, "cfam-reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + if (!gpio) + return 0; + + aspeed->cfam_reset_gpio = gpio; + + rc = device_create_file(dev, &dev_attr_cfam_reset); + if (rc) { + devm_gpiod_put(dev, gpio); + return rc; + } + + return 0; +} + static int tacoma_cabled_fsi_fixup(struct device *dev) { struct gpio_desc *routing_gpio, *mux_gpio; @@ -507,6 +545,11 @@ static int fsi_master_aspeed_probe(struct platform_device *pdev) return rc; } + rc = setup_cfam_reset(aspeed); + if (rc) { + dev_err(&pdev->dev, "CFAM reset GPIO setup failed\n"); + } + writel(0x1, aspeed->base + OPB_CLK_SYNC); writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN, aspeed->base + OPB_IRQ_MASK); -- cgit v1.2.3