brintos

brintos / linux-shallow public Read only

0
0
Text · 16.2 KiB · 6f5e1bd Raw
675 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2// Copyright (C) IBM Corporation 20183// FSI master driver for AST26004 5#include <linux/clk.h>6#include <linux/delay.h>7#include <linux/fsi.h>8#include <linux/io.h>9#include <linux/mfd/syscon.h>10#include <linux/module.h>11#include <linux/mutex.h>12#include <linux/of.h>13#include <linux/platform_device.h>14#include <linux/regmap.h>15#include <linux/slab.h>16#include <linux/iopoll.h>17#include <linux/gpio/consumer.h>18 19#include "fsi-master.h"20 21struct fsi_master_aspeed {22	struct fsi_master	master;23	struct mutex		lock;	/* protect HW access */24	struct device		*dev;25	void __iomem		*base;26	struct clk		*clk;27	struct gpio_desc	*cfam_reset_gpio;28};29 30#define to_fsi_master_aspeed(m) \31	container_of(m, struct fsi_master_aspeed, master)32 33/* Control register (size 0x400) */34static const u32 ctrl_base = 0x80000000;35 36static const u32 fsi_base = 0xa0000000;37 38#define OPB_FSI_VER	0x0039#define OPB_TRIGGER	0x0440#define OPB_CTRL_BASE	0x0841#define OPB_FSI_BASE	0x0c42#define OPB_CLK_SYNC	0x3c43#define OPB_IRQ_CLEAR	0x4044#define OPB_IRQ_MASK	0x4445#define OPB_IRQ_STATUS	0x4846 47#define OPB0_SELECT	0x1048#define OPB0_RW		0x1449#define OPB0_XFER_SIZE	0x1850#define OPB0_FSI_ADDR	0x1c51#define OPB0_FSI_DATA_W	0x2052#define OPB0_STATUS	0x8053#define OPB0_FSI_DATA_R	0x8454 55#define OPB0_WRITE_ORDER1	0x4c56#define OPB0_WRITE_ORDER2	0x5057#define OPB1_WRITE_ORDER1	0x5458#define OPB1_WRITE_ORDER2	0x5859#define OPB0_READ_ORDER1	0x5c60#define OPB1_READ_ORDER2	0x6061 62#define OPB_RETRY_COUNTER	0x6463 64/* OPBn_STATUS */65#define STATUS_HALFWORD_ACK	BIT(0)66#define STATUS_FULLWORD_ACK	BIT(1)67#define STATUS_ERR_ACK		BIT(2)68#define STATUS_RETRY		BIT(3)69#define STATUS_TIMEOUT		BIT(4)70 71/* OPB_IRQ_MASK */72#define OPB1_XFER_ACK_EN BIT(17)73#define OPB0_XFER_ACK_EN BIT(16)74 75/* OPB_RW */76#define CMD_READ	BIT(0)77#define CMD_WRITE	078 79/* OPBx_XFER_SIZE */80#define XFER_FULLWORD	(BIT(1) | BIT(0))81#define XFER_HALFWORD	(BIT(0))82#define XFER_BYTE	(0)83 84#define CREATE_TRACE_POINTS85#include <trace/events/fsi_master_aspeed.h>86 87#define FSI_LINK_ENABLE_SETUP_TIME	10	/* in mS */88 89/* Run the bus at maximum speed by default */90#define FSI_DIVISOR_DEFAULT            191#define FSI_DIVISOR_CABLED             292static u16 aspeed_fsi_divisor = FSI_DIVISOR_DEFAULT;93module_param_named(bus_div,aspeed_fsi_divisor, ushort, 0);94 95#define OPB_POLL_TIMEOUT		50096 97static int __opb_write(struct fsi_master_aspeed *aspeed, u32 addr,98		       u32 val, u32 transfer_size)99{100	void __iomem *base = aspeed->base;101	u32 reg, status;102	int ret;103 104	/*105	 * The ordering of these writes up until the trigger106	 * write does not matter, so use writel_relaxed.107	 */108	writel_relaxed(CMD_WRITE, base + OPB0_RW);109	writel_relaxed(transfer_size, base + OPB0_XFER_SIZE);110	writel_relaxed(addr, base + OPB0_FSI_ADDR);111	writel_relaxed(val, base + OPB0_FSI_DATA_W);112	writel_relaxed(0x1, base + OPB_IRQ_CLEAR);113	writel(0x1, base + OPB_TRIGGER);114 115	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,116				(reg & OPB0_XFER_ACK_EN) != 0,117				0, OPB_POLL_TIMEOUT);118 119	status = readl(base + OPB0_STATUS);120 121	trace_fsi_master_aspeed_opb_write(addr, val, transfer_size, status, reg);122 123	/* Return error when poll timed out */124	if (ret)125		return ret;126 127	/* Command failed, master will reset */128	if (status & STATUS_ERR_ACK)129		return -EIO;130 131	return 0;132}133 134static int opb_writeb(struct fsi_master_aspeed *aspeed, u32 addr, u8 val)135{136	return __opb_write(aspeed, addr, val, XFER_BYTE);137}138 139static int opb_writew(struct fsi_master_aspeed *aspeed, u32 addr, __be16 val)140{141	return __opb_write(aspeed, addr, (__force u16)val, XFER_HALFWORD);142}143 144static int opb_writel(struct fsi_master_aspeed *aspeed, u32 addr, __be32 val)145{146	return __opb_write(aspeed, addr, (__force u32)val, XFER_FULLWORD);147}148 149static int __opb_read(struct fsi_master_aspeed *aspeed, uint32_t addr,150		      u32 transfer_size, void *out)151{152	void __iomem *base = aspeed->base;153	u32 result, reg;154	int status, ret;155 156	/*157	 * The ordering of these writes up until the trigger158	 * write does not matter, so use writel_relaxed.159	 */160	writel_relaxed(CMD_READ, base + OPB0_RW);161	writel_relaxed(transfer_size, base + OPB0_XFER_SIZE);162	writel_relaxed(addr, base + OPB0_FSI_ADDR);163	writel_relaxed(0x1, base + OPB_IRQ_CLEAR);164	writel(0x1, base + OPB_TRIGGER);165 166	ret = readl_poll_timeout(base + OPB_IRQ_STATUS, reg,167			   (reg & OPB0_XFER_ACK_EN) != 0,168			   0, OPB_POLL_TIMEOUT);169 170	status = readl(base + OPB0_STATUS);171 172	result = readl(base + OPB0_FSI_DATA_R);173 174	trace_fsi_master_aspeed_opb_read(addr, transfer_size, result,175			readl(base + OPB0_STATUS),176			reg);177 178	/* Return error when poll timed out */179	if (ret)180		return ret;181 182	/* Command failed, master will reset */183	if (status & STATUS_ERR_ACK)184		return -EIO;185 186	if (out) {187		switch (transfer_size) {188		case XFER_BYTE:189			*(u8 *)out = result;190			break;191		case XFER_HALFWORD:192			*(u16 *)out = result;193			break;194		case XFER_FULLWORD:195			*(u32 *)out = result;196			break;197		default:198			return -EINVAL;199		}200 201	}202 203	return 0;204}205 206static int opb_readl(struct fsi_master_aspeed *aspeed, uint32_t addr, __be32 *out)207{208	return __opb_read(aspeed, addr, XFER_FULLWORD, out);209}210 211static int opb_readw(struct fsi_master_aspeed *aspeed, uint32_t addr, __be16 *out)212{213	return __opb_read(aspeed, addr, XFER_HALFWORD, (void *)out);214}215 216static int opb_readb(struct fsi_master_aspeed *aspeed, uint32_t addr, u8 *out)217{218	return __opb_read(aspeed, addr, XFER_BYTE, (void *)out);219}220 221static int check_errors(struct fsi_master_aspeed *aspeed, int err)222{223	int ret;224 225	if (trace_fsi_master_aspeed_opb_error_enabled()) {226		__be32 mresp0, mstap0, mesrb0;227 228		opb_readl(aspeed, ctrl_base + FSI_MRESP0, &mresp0);229		opb_readl(aspeed, ctrl_base + FSI_MSTAP0, &mstap0);230		opb_readl(aspeed, ctrl_base + FSI_MESRB0, &mesrb0);231 232		trace_fsi_master_aspeed_opb_error(233				be32_to_cpu(mresp0),234				be32_to_cpu(mstap0),235				be32_to_cpu(mesrb0));236	}237 238	if (err == -EIO) {239		/* Check MAEB (0x70) ? */240 241		/* Then clear errors in master */242		ret = opb_writel(aspeed, ctrl_base + FSI_MRESP0,243				cpu_to_be32(FSI_MRESP_RST_ALL_MASTER));244		if (ret) {245			/* TODO: log? return different code? */246			return ret;247		}248		/* TODO: confirm that 0x70 was okay */249	}250 251	/* This will pass through timeout errors */252	return err;253}254 255static int aspeed_master_read(struct fsi_master *master, int link,256			uint8_t id, uint32_t addr, void *val, size_t size)257{258	struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);259	int ret;260 261	if (id > 0x3)262		return -EINVAL;263 264	addr |= id << 21;265	addr += link * FSI_HUB_LINK_SIZE;266 267	mutex_lock(&aspeed->lock);268 269	switch (size) {270	case 1:271		ret = opb_readb(aspeed, fsi_base + addr, val);272		break;273	case 2:274		ret = opb_readw(aspeed, fsi_base + addr, val);275		break;276	case 4:277		ret = opb_readl(aspeed, fsi_base + addr, val);278		break;279	default:280		ret = -EINVAL;281		goto done;282	}283 284	ret = check_errors(aspeed, ret);285done:286	mutex_unlock(&aspeed->lock);287	return ret;288}289 290static int aspeed_master_write(struct fsi_master *master, int link,291			uint8_t id, uint32_t addr, const void *val, size_t size)292{293	struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);294	int ret;295 296	if (id > 0x3)297		return -EINVAL;298 299	addr |= id << 21;300	addr += link * FSI_HUB_LINK_SIZE;301 302	mutex_lock(&aspeed->lock);303 304	switch (size) {305	case 1:306		ret = opb_writeb(aspeed, fsi_base + addr, *(u8 *)val);307		break;308	case 2:309		ret = opb_writew(aspeed, fsi_base + addr, *(__be16 *)val);310		break;311	case 4:312		ret = opb_writel(aspeed, fsi_base + addr, *(__be32 *)val);313		break;314	default:315		ret = -EINVAL;316		goto done;317	}318 319	ret = check_errors(aspeed, ret);320done:321	mutex_unlock(&aspeed->lock);322	return ret;323}324 325static int aspeed_master_link_enable(struct fsi_master *master, int link,326				     bool enable)327{328	struct fsi_master_aspeed *aspeed = to_fsi_master_aspeed(master);329	int idx, bit, ret;330	__be32 reg;331 332	idx = link / 32;333	bit = link % 32;334 335	reg = cpu_to_be32(0x80000000 >> bit);336 337	mutex_lock(&aspeed->lock);338 339	if (!enable) {340		ret = opb_writel(aspeed, ctrl_base + FSI_MCENP0 + (4 * idx), reg);341		goto done;342	}343 344	ret = opb_writel(aspeed, ctrl_base + FSI_MSENP0 + (4 * idx), reg);345	if (ret)346		goto done;347 348	mdelay(FSI_LINK_ENABLE_SETUP_TIME);349done:350	mutex_unlock(&aspeed->lock);351	return ret;352}353 354static int aspeed_master_term(struct fsi_master *master, int link, uint8_t id)355{356	uint32_t addr;357	__be32 cmd;358 359	addr = 0x4;360	cmd = cpu_to_be32(0xecc00000);361 362	return aspeed_master_write(master, link, id, addr, &cmd, 4);363}364 365static int aspeed_master_break(struct fsi_master *master, int link)366{367	uint32_t addr;368	__be32 cmd;369 370	addr = 0x0;371	cmd = cpu_to_be32(0xc0de0000);372 373	return aspeed_master_write(master, link, 0, addr, &cmd, 4);374}375 376static void aspeed_master_release(struct device *dev)377{378	struct fsi_master_aspeed *aspeed =379		to_fsi_master_aspeed(to_fsi_master(dev));380 381	kfree(aspeed);382}383 384/* mmode encoders */385static inline u32 fsi_mmode_crs0(u32 x)386{387	return (x & FSI_MMODE_CRS0MASK) << FSI_MMODE_CRS0SHFT;388}389 390static inline u32 fsi_mmode_crs1(u32 x)391{392	return (x & FSI_MMODE_CRS1MASK) << FSI_MMODE_CRS1SHFT;393}394 395static int aspeed_master_init(struct fsi_master_aspeed *aspeed)396{397	__be32 reg;398 399	reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK400			| FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);401	opb_writel(aspeed, ctrl_base + FSI_MRESP0, reg);402 403	/* Initialize the MFSI (hub master) engine */404	reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK405			| FSI_MRESP_RST_MCR | FSI_MRESP_RST_PYE);406	opb_writel(aspeed, ctrl_base + FSI_MRESP0, reg);407 408	reg = cpu_to_be32(FSI_MECTRL_EOAE | FSI_MECTRL_P8_AUTO_TERM);409	opb_writel(aspeed, ctrl_base + FSI_MECTRL, reg);410 411	reg = cpu_to_be32(FSI_MMODE_ECRC | FSI_MMODE_EPC | FSI_MMODE_RELA412			| fsi_mmode_crs0(aspeed_fsi_divisor)413			| fsi_mmode_crs1(aspeed_fsi_divisor)414			| FSI_MMODE_P8_TO_LSB);415	dev_info(aspeed->dev, "mmode set to %08x (divisor %d)\n",416			be32_to_cpu(reg), aspeed_fsi_divisor);417	opb_writel(aspeed, ctrl_base + FSI_MMODE, reg);418 419	reg = cpu_to_be32(0xffff0000);420	opb_writel(aspeed, ctrl_base + FSI_MDLYR, reg);421 422	reg = cpu_to_be32(~0);423	opb_writel(aspeed, ctrl_base + FSI_MSENP0, reg);424 425	/* Leave enabled long enough for master logic to set up */426	mdelay(FSI_LINK_ENABLE_SETUP_TIME);427 428	opb_writel(aspeed, ctrl_base + FSI_MCENP0, reg);429 430	opb_readl(aspeed, ctrl_base + FSI_MAEB, NULL);431 432	reg = cpu_to_be32(FSI_MRESP_RST_ALL_MASTER | FSI_MRESP_RST_ALL_LINK);433	opb_writel(aspeed, ctrl_base + FSI_MRESP0, reg);434 435	opb_readl(aspeed, ctrl_base + FSI_MLEVP0, NULL);436 437	/* Reset the master bridge */438	reg = cpu_to_be32(FSI_MRESB_RST_GEN);439	opb_writel(aspeed, ctrl_base + FSI_MRESB0, reg);440 441	reg = cpu_to_be32(FSI_MRESB_RST_ERR);442	opb_writel(aspeed, ctrl_base + FSI_MRESB0, reg);443 444	return 0;445}446 447static ssize_t cfam_reset_store(struct device *dev, struct device_attribute *attr,448				const char *buf, size_t count)449{450	struct fsi_master_aspeed *aspeed = dev_get_drvdata(dev);451 452	trace_fsi_master_aspeed_cfam_reset(true);453	mutex_lock(&aspeed->lock);454	gpiod_set_value(aspeed->cfam_reset_gpio, 1);455	usleep_range(900, 1000);456	gpiod_set_value(aspeed->cfam_reset_gpio, 0);457	usleep_range(900, 1000);458	opb_writel(aspeed, ctrl_base + FSI_MRESP0, cpu_to_be32(FSI_MRESP_RST_ALL_MASTER));459	mutex_unlock(&aspeed->lock);460	trace_fsi_master_aspeed_cfam_reset(false);461 462	return count;463}464 465static DEVICE_ATTR(cfam_reset, 0200, NULL, cfam_reset_store);466 467static int setup_cfam_reset(struct fsi_master_aspeed *aspeed)468{469	struct device *dev = aspeed->dev;470	struct gpio_desc *gpio;471	int rc;472 473	gpio = devm_gpiod_get_optional(dev, "cfam-reset", GPIOD_OUT_LOW);474	if (IS_ERR(gpio))475		return PTR_ERR(gpio);476	if (!gpio)477		return 0;478 479	aspeed->cfam_reset_gpio = gpio;480 481	rc = device_create_file(dev, &dev_attr_cfam_reset);482	if (rc) {483		devm_gpiod_put(dev, gpio);484		return rc;485	}486 487	return 0;488}489 490static int tacoma_cabled_fsi_fixup(struct device *dev)491{492	struct gpio_desc *routing_gpio, *mux_gpio;493	int gpio;494 495	/*496	 * The routing GPIO is a jumper indicating we should mux for the497	 * externally connected FSI cable.498	 */499	routing_gpio = devm_gpiod_get_optional(dev, "fsi-routing",500			GPIOD_IN | GPIOD_FLAGS_BIT_NONEXCLUSIVE);501	if (IS_ERR(routing_gpio))502		return PTR_ERR(routing_gpio);503	if (!routing_gpio)504		return 0;505 506	mux_gpio = devm_gpiod_get_optional(dev, "fsi-mux", GPIOD_ASIS);507	if (IS_ERR(mux_gpio))508		return PTR_ERR(mux_gpio);509	if (!mux_gpio)510		return 0;511 512	gpio = gpiod_get_value(routing_gpio);513	if (gpio < 0)514		return gpio;515 516	/* If the routing GPIO is high we should set the mux to low. */517	if (gpio) {518		/*519		 * Cable signal integrity means we should run the bus520		 * slightly slower. Do not override if a kernel param521		 * has already overridden.522		 */523		if (aspeed_fsi_divisor == FSI_DIVISOR_DEFAULT)524			aspeed_fsi_divisor = FSI_DIVISOR_CABLED;525 526		gpiod_direction_output(mux_gpio, 0);527		dev_info(dev, "FSI configured for external cable\n");528	} else {529		gpiod_direction_output(mux_gpio, 1);530	}531 532	devm_gpiod_put(dev, routing_gpio);533 534	return 0;535}536 537static int fsi_master_aspeed_probe(struct platform_device *pdev)538{539	struct fsi_master_aspeed *aspeed;540	int rc, links, reg;541	__be32 raw;542 543	rc = tacoma_cabled_fsi_fixup(&pdev->dev);544	if (rc) {545		dev_err(&pdev->dev, "Tacoma FSI cable fixup failed\n");546		return rc;547	}548 549	aspeed = kzalloc(sizeof(*aspeed), GFP_KERNEL);550	if (!aspeed)551		return -ENOMEM;552 553	aspeed->dev = &pdev->dev;554 555	aspeed->base = devm_platform_ioremap_resource(pdev, 0);556	if (IS_ERR(aspeed->base)) {557		rc = PTR_ERR(aspeed->base);558		goto err_free_aspeed;559	}560 561	aspeed->clk = devm_clk_get(aspeed->dev, NULL);562	if (IS_ERR(aspeed->clk)) {563		dev_err(aspeed->dev, "couldn't get clock\n");564		rc = PTR_ERR(aspeed->clk);565		goto err_free_aspeed;566	}567	rc = clk_prepare_enable(aspeed->clk);568	if (rc) {569		dev_err(aspeed->dev, "couldn't enable clock\n");570		goto err_free_aspeed;571	}572 573	rc = setup_cfam_reset(aspeed);574	if (rc) {575		dev_err(&pdev->dev, "CFAM reset GPIO setup failed\n");576	}577 578	writel(0x1, aspeed->base + OPB_CLK_SYNC);579	writel(OPB1_XFER_ACK_EN | OPB0_XFER_ACK_EN,580			aspeed->base + OPB_IRQ_MASK);581 582	/* TODO: determine an appropriate value */583	writel(0x10, aspeed->base + OPB_RETRY_COUNTER);584 585	writel(ctrl_base, aspeed->base + OPB_CTRL_BASE);586	writel(fsi_base, aspeed->base + OPB_FSI_BASE);587 588	/* Set read data order */589	writel(0x00030b1b, aspeed->base + OPB0_READ_ORDER1);590 591	/* Set write data order */592	writel(0x0011101b, aspeed->base + OPB0_WRITE_ORDER1);593	writel(0x0c330f3f, aspeed->base + OPB0_WRITE_ORDER2);594 595	/*596	 * Select OPB0 for all operations.597	 * Will need to be reworked when enabling DMA or anything that uses598	 * OPB1.599	 */600	writel(0x1, aspeed->base + OPB0_SELECT);601 602	rc = opb_readl(aspeed, ctrl_base + FSI_MVER, &raw);603	if (rc) {604		dev_err(&pdev->dev, "failed to read hub version\n");605		goto err_release;606	}607 608	reg = be32_to_cpu(raw);609	links = (reg >> 8) & 0xff;610	dev_info(&pdev->dev, "hub version %08x (%d links)\n", reg, links);611 612	aspeed->master.dev.parent = &pdev->dev;613	aspeed->master.dev.release = aspeed_master_release;614	aspeed->master.dev.of_node = of_node_get(dev_of_node(&pdev->dev));615 616	aspeed->master.n_links = links;617	aspeed->master.read = aspeed_master_read;618	aspeed->master.write = aspeed_master_write;619	aspeed->master.send_break = aspeed_master_break;620	aspeed->master.term = aspeed_master_term;621	aspeed->master.link_enable = aspeed_master_link_enable;622 623	dev_set_drvdata(&pdev->dev, aspeed);624 625	mutex_init(&aspeed->lock);626	aspeed_master_init(aspeed);627 628	rc = fsi_master_register(&aspeed->master);629	if (rc)630		goto err_release;631 632	/* At this point, fsi_master_register performs the device_initialize(),633	 * and holds the sole reference on master.dev. This means the device634	 * will be freed (via ->release) during any subsequent call to635	 * fsi_master_unregister.  We add our own reference to it here, so we636	 * can perform cleanup (in _remove()) without it being freed before637	 * we're ready.638	 */639	get_device(&aspeed->master.dev);640	return 0;641 642err_release:643	clk_disable_unprepare(aspeed->clk);644err_free_aspeed:645	kfree(aspeed);646	return rc;647}648 649static void fsi_master_aspeed_remove(struct platform_device *pdev)650{651	struct fsi_master_aspeed *aspeed = platform_get_drvdata(pdev);652 653	fsi_master_unregister(&aspeed->master);654	clk_disable_unprepare(aspeed->clk);655}656 657static const struct of_device_id fsi_master_aspeed_match[] = {658	{ .compatible = "aspeed,ast2600-fsi-master" },659	{ },660};661MODULE_DEVICE_TABLE(of, fsi_master_aspeed_match);662 663static struct platform_driver fsi_master_aspeed_driver = {664	.driver = {665		.name		= "fsi-master-aspeed",666		.of_match_table	= fsi_master_aspeed_match,667	},668	.probe	= fsi_master_aspeed_probe,669	.remove_new = fsi_master_aspeed_remove,670};671 672module_platform_driver(fsi_master_aspeed_driver);673MODULE_DESCRIPTION("FSI master driver for AST2600");674MODULE_LICENSE("GPL");675