Commit f7dbcd17 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman
Browse files

Merge tag 'fsi-for-5.10' of...

Merge tag 'fsi-for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi into char-misc-next

Joel writes:

FSI changes for 5.10

 - Misc code cleanups. Thanks to Colin, Xu and Rikard

 - Features for the ASPEED FSI master
  * Detect connection type and routing for Tacoma
  * Run at full speed (200MHz) by default
  * Set bus speed with a parameter
  * CFAM reset GPIO
  * 23 bit addressing

 - Core features
  * Disable unused links
  * Set LBUS ownership

* tag 'fsi-for-5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/joel/fsi:
  fsi: aspeed: Support CFAM reset GPIO
  fsi: aspeed: Add module param for bus divisor
  fsi: aspeed: Run the bus at maximum speed
  fsi: aspeed: Support cabled FSI
  dt-bindings: fsi: Document gpios
  fsi: scom: Constify scom_ids
  fsi: sbefifo: Constify sbefifo_ids
  fsi: master: Constify hub_master_ids
  fsi: master: Remove link enable read-back
  fsi: core: Set slave local bus ownership during init
  fsi: core: Disable link when slave init fails
  fsi: master: Add boolean parameter to link_enable function
  fsi: fsi-occ: fix return value check in occ_probe()
  fsi: aspeed: Enable 23-bit addressing
  fsi: master-ast-cf: fix spelling mistake "firwmare" -> "firmware"
parents d210a002 4a851d71
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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.
+12 −0
Original line number Diff line number Diff line
@@ -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>;
    };
+28 −3
Original line number Diff line number Diff line
@@ -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,
@@ -1154,10 +1168,18 @@ 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)
		return master->link_enable(master, link);
		return master->link_enable(master, link, true);

	return 0;
}
@@ -1192,12 +1214,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;
+118 −16
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/iopoll.h>
#include <linux/gpio/consumer.h>

#include "fsi-master.h"

@@ -21,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) \
@@ -82,7 +84,12 @@ 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;
module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0);

#define OPB_POLL_TIMEOUT		10000

static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr,
@@ -241,9 +248,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 +281,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) {
@@ -299,32 +308,28 @@ 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;
	__be32 reg, result;
	__be32 reg;

	idx = link / 32;
	bit = link % 32;

	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;

	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;
}

@@ -386,9 +391,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);
@@ -419,6 +426,90 @@ 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;
	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) {
		/*
		 * Cable signal integrity means we should run the bus
		 * slightly slower. Do not override if a kernel param
		 * has already overridden.
		 */
		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 {
		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;
@@ -426,6 +517,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;
@@ -448,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);
+4 −3
Original line number Diff line number Diff line
@@ -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;
	}
@@ -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);
Loading