brintos

brintos / linux-shallow public Read only

0
0
Text · 8.4 KiB · 4577e80 Raw
332 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright (C) 2020 BAIKAL ELECTRONICS, JSC4//5// Authors:6//   Ramil Zaripov <Ramil.Zaripov@baikalelectronics.ru>7//   Serge Semin <Sergey.Semin@baikalelectronics.ru>8//9// Baikal-T1 DW APB SPI and System Boot SPI driver10//11 12#include <linux/clk.h>13#include <linux/cpumask.h>14#include <linux/err.h>15#include <linux/interrupt.h>16#include <linux/module.h>17#include <linux/mux/consumer.h>18#include <linux/of.h>19#include <linux/of_platform.h>20#include <linux/platform_device.h>21#include <linux/pm_runtime.h>22#include <linux/property.h>23#include <linux/slab.h>24#include <linux/spi/spi-mem.h>25#include <linux/spi/spi.h>26 27#include "spi-dw.h"28 29#define BT1_BOOT_DIRMAP		030#define BT1_BOOT_REGS		131 32struct dw_spi_bt1 {33	struct dw_spi		dws;34	struct clk		*clk;35	struct mux_control	*mux;36 37#ifdef CONFIG_SPI_DW_BT1_DIRMAP38	void __iomem		*map;39	resource_size_t		map_len;40#endif41};42#define to_dw_spi_bt1(_ctlr) \43	container_of(spi_controller_get_devdata(_ctlr), struct dw_spi_bt1, dws)44 45typedef int (*dw_spi_bt1_init_cb)(struct platform_device *pdev,46				    struct dw_spi_bt1 *dwsbt1);47 48#ifdef CONFIG_SPI_DW_BT1_DIRMAP49 50static int dw_spi_bt1_dirmap_create(struct spi_mem_dirmap_desc *desc)51{52	struct dw_spi_bt1 *dwsbt1 = to_dw_spi_bt1(desc->mem->spi->controller);53 54	if (!dwsbt1->map ||55	    !dwsbt1->dws.mem_ops.supports_op(desc->mem, &desc->info.op_tmpl))56		return -EOPNOTSUPP;57 58	if (desc->info.op_tmpl.data.dir != SPI_MEM_DATA_IN)59		return -EOPNOTSUPP;60 61	/*62	 * Make sure the requested region doesn't go out of the physically63	 * mapped flash memory bounds.64	 */65	if (desc->info.offset + desc->info.length > dwsbt1->map_len)66		return -EINVAL;67 68	return 0;69}70 71/*72 * Directly mapped SPI memory region is only accessible in the dword chunks.73 * That's why we have to create a dedicated read-method to copy data from there74 * to the passed buffer.75 */76static void dw_spi_bt1_dirmap_copy_from_map(void *to, void __iomem *from, size_t len)77{78	size_t shift, chunk;79	u32 data;80 81	/*82	 * We split the copying up into the next three stages: unaligned head,83	 * aligned body, unaligned tail.84	 */85	shift = (size_t)from & 0x3;86	if (shift) {87		chunk = min_t(size_t, 4 - shift, len);88		data = readl_relaxed(from - shift);89		memcpy(to, (char *)&data + shift, chunk);90		from += chunk;91		to += chunk;92		len -= chunk;93	}94 95	while (len >= 4) {96		data = readl_relaxed(from);97		memcpy(to, &data, 4);98		from += 4;99		to += 4;100		len -= 4;101	}102 103	if (len) {104		data = readl_relaxed(from);105		memcpy(to, &data, len);106	}107}108 109static ssize_t dw_spi_bt1_dirmap_read(struct spi_mem_dirmap_desc *desc,110				      u64 offs, size_t len, void *buf)111{112	struct dw_spi_bt1 *dwsbt1 = to_dw_spi_bt1(desc->mem->spi->controller);113	struct dw_spi *dws = &dwsbt1->dws;114	struct spi_mem *mem = desc->mem;115	struct dw_spi_cfg cfg;116	int ret;117 118	/*119	 * Make sure the requested operation length is valid. Truncate the120	 * length if it's greater than the length of the MMIO region.121	 */122	if (offs >= dwsbt1->map_len || !len)123		return 0;124 125	len = min_t(size_t, len, dwsbt1->map_len - offs);126 127	/* Collect the controller configuration required by the operation */128	cfg.tmode = DW_SPI_CTRLR0_TMOD_EPROMREAD;129	cfg.dfs = 8;130	cfg.ndf = 4;131	cfg.freq = mem->spi->max_speed_hz;132 133	/* Make sure the corresponding CS is de-asserted on transmission */134	dw_spi_set_cs(mem->spi, false);135 136	dw_spi_enable_chip(dws, 0);137 138	dw_spi_update_config(dws, mem->spi, &cfg);139 140	dw_spi_umask_intr(dws, DW_SPI_INT_RXFI);141 142	dw_spi_enable_chip(dws, 1);143 144	/*145	 * Enable the transparent mode of the System Boot Controller.146	 * The SPI core IO should have been locked before calling this method147	 * so noone would be touching the controller' registers during the148	 * dirmap operation.149	 */150	ret = mux_control_select(dwsbt1->mux, BT1_BOOT_DIRMAP);151	if (ret)152		return ret;153 154	dw_spi_bt1_dirmap_copy_from_map(buf, dwsbt1->map + offs, len);155 156	mux_control_deselect(dwsbt1->mux);157 158	dw_spi_set_cs(mem->spi, true);159 160	ret = dw_spi_check_status(dws, true);161 162	return ret ?: len;163}164 165#endif /* CONFIG_SPI_DW_BT1_DIRMAP */166 167static int dw_spi_bt1_std_init(struct platform_device *pdev,168			       struct dw_spi_bt1 *dwsbt1)169{170	struct dw_spi *dws = &dwsbt1->dws;171 172	dws->irq = platform_get_irq(pdev, 0);173	if (dws->irq < 0)174		return dws->irq;175 176	dws->num_cs = 4;177 178	/*179	 * Baikal-T1 Normal SPI Controllers don't always keep up with full SPI180	 * bus speed especially when it comes to the concurrent access to the181	 * APB bus resources. Thus we have no choice but to set a constraint on182	 * the SPI bus frequency for the memory operations which require to183	 * read/write data as fast as possible.184	 */185	dws->max_mem_freq = 20000000U;186 187	dw_spi_dma_setup_generic(dws);188 189	return 0;190}191 192static int dw_spi_bt1_sys_init(struct platform_device *pdev,193			       struct dw_spi_bt1 *dwsbt1)194{195	struct resource *mem __maybe_unused;196	struct dw_spi *dws = &dwsbt1->dws;197 198	/*199	 * Baikal-T1 System Boot Controller is equipped with a mux, which200	 * switches between the directly mapped SPI flash access mode and201	 * IO access to the DW APB SSI registers. Note the mux controller202	 * must be setup to preserve the registers being accessible by default203	 * (on idle-state).204	 */205	dwsbt1->mux = devm_mux_control_get(&pdev->dev, NULL);206	if (IS_ERR(dwsbt1->mux))207		return PTR_ERR(dwsbt1->mux);208 209	/*210	 * Directly mapped SPI flash memory is a 16MB MMIO region, which can be211	 * used to access a peripheral memory device just by reading/writing212	 * data from/to it. Note the system APB bus will stall during each IO213	 * from/to the dirmap region until the operation is finished. So don't214	 * use it concurrently with time-critical tasks (like the SPI memory215	 * operations implemented in the DW APB SSI driver).216	 */217#ifdef CONFIG_SPI_DW_BT1_DIRMAP218	mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);219	if (mem) {220		dwsbt1->map = devm_ioremap_resource(&pdev->dev, mem);221		if (!IS_ERR(dwsbt1->map)) {222			dwsbt1->map_len = resource_size(mem);223			dws->mem_ops.dirmap_create = dw_spi_bt1_dirmap_create;224			dws->mem_ops.dirmap_read = dw_spi_bt1_dirmap_read;225		} else {226			dwsbt1->map = NULL;227		}228	}229#endif /* CONFIG_SPI_DW_BT1_DIRMAP */230 231	/*232	 * There is no IRQ, no DMA and just one CS available on the System Boot233	 * SPI controller.234	 */235	dws->irq = IRQ_NOTCONNECTED;236	dws->num_cs = 1;237 238	/*239	 * Baikal-T1 System Boot SPI Controller doesn't keep up with the full240	 * SPI bus speed due to relatively slow APB bus and races for it'241	 * resources from different CPUs. The situation is worsen by a small242	 * FIFOs depth (just 8 words). It works better in a single CPU mode243	 * though, but still tends to be not fast enough at low CPU244	 * frequencies.245	 */246	if (num_possible_cpus() > 1)247		dws->max_mem_freq = 10000000U;248	else249		dws->max_mem_freq = 20000000U;250 251	return 0;252}253 254static int dw_spi_bt1_probe(struct platform_device *pdev)255{256	dw_spi_bt1_init_cb init_func;257	struct dw_spi_bt1 *dwsbt1;258	struct resource *mem;259	struct dw_spi *dws;260	int ret;261 262	dwsbt1 = devm_kzalloc(&pdev->dev, sizeof(struct dw_spi_bt1), GFP_KERNEL);263	if (!dwsbt1)264		return -ENOMEM;265 266	dws = &dwsbt1->dws;267 268	dws->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &mem);269	if (IS_ERR(dws->regs))270		return PTR_ERR(dws->regs);271 272	dws->paddr = mem->start;273 274	dwsbt1->clk = devm_clk_get_enabled(&pdev->dev, NULL);275	if (IS_ERR(dwsbt1->clk))276		return PTR_ERR(dwsbt1->clk);277 278	dws->bus_num = pdev->id;279	dws->reg_io_width = 4;280	dws->max_freq = clk_get_rate(dwsbt1->clk);281	if (!dws->max_freq)282		return -EINVAL;283 284	init_func = device_get_match_data(&pdev->dev);285	ret = init_func(pdev, dwsbt1);286	if (ret)287		return ret;288 289	pm_runtime_enable(&pdev->dev);290 291	ret = dw_spi_add_host(&pdev->dev, dws);292	if (ret) {293		pm_runtime_disable(&pdev->dev);294		return ret;295	}296 297	platform_set_drvdata(pdev, dwsbt1);298 299	return 0;300}301 302static void dw_spi_bt1_remove(struct platform_device *pdev)303{304	struct dw_spi_bt1 *dwsbt1 = platform_get_drvdata(pdev);305 306	dw_spi_remove_host(&dwsbt1->dws);307 308	pm_runtime_disable(&pdev->dev);309}310 311static const struct of_device_id dw_spi_bt1_of_match[] = {312	{ .compatible = "baikal,bt1-ssi", .data = dw_spi_bt1_std_init},313	{ .compatible = "baikal,bt1-sys-ssi", .data = dw_spi_bt1_sys_init},314	{ }315};316MODULE_DEVICE_TABLE(of, dw_spi_bt1_of_match);317 318static struct platform_driver dw_spi_bt1_driver = {319	.probe	= dw_spi_bt1_probe,320	.remove_new = dw_spi_bt1_remove,321	.driver	= {322		.name		= "bt1-sys-ssi",323		.of_match_table	= dw_spi_bt1_of_match,324	},325};326module_platform_driver(dw_spi_bt1_driver);327 328MODULE_AUTHOR("Serge Semin <Sergey.Semin@baikalelectronics.ru>");329MODULE_DESCRIPTION("Baikal-T1 System Boot SPI Controller driver");330MODULE_LICENSE("GPL v2");331MODULE_IMPORT_NS(SPI_DW_CORE);332