cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

bus_spi.c (7526B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * SPI interface.
      4 *
      5 * Copyright (c) 2017-2020, Silicon Laboratories, Inc.
      6 * Copyright (c) 2011, Sagrad Inc.
      7 * Copyright (c) 2010, ST-Ericsson
      8 */
      9#include <linux/module.h>
     10#include <linux/delay.h>
     11#include <linux/gpio/consumer.h>
     12#include <linux/spi/spi.h>
     13#include <linux/interrupt.h>
     14#include <linux/irq.h>
     15#include <linux/of.h>
     16
     17#include "bus.h"
     18#include "wfx.h"
     19#include "hwio.h"
     20#include "main.h"
     21#include "bh.h"
     22
     23#define SET_WRITE 0x7FFF        /* usage: and operation */
     24#define SET_READ 0x8000         /* usage: or operation */
     25
     26static const struct wfx_platform_data pdata_wf200 = {
     27	.file_fw = "wfx/wfm_wf200",
     28	.file_pds = "wfx/wf200.pds",
     29	.use_rising_clk = true,
     30};
     31
     32static const struct wfx_platform_data pdata_brd4001a = {
     33	.file_fw = "wfx/wfm_wf200",
     34	.file_pds = "wfx/brd4001a.pds",
     35	.use_rising_clk = true,
     36};
     37
     38static const struct wfx_platform_data pdata_brd8022a = {
     39	.file_fw = "wfx/wfm_wf200",
     40	.file_pds = "wfx/brd8022a.pds",
     41	.use_rising_clk = true,
     42};
     43
     44static const struct wfx_platform_data pdata_brd8023a = {
     45	.file_fw = "wfx/wfm_wf200",
     46	.file_pds = "wfx/brd8023a.pds",
     47	.use_rising_clk = true,
     48};
     49
     50struct wfx_spi_priv {
     51	struct spi_device *func;
     52	struct wfx_dev *core;
     53	struct gpio_desc *gpio_reset;
     54	bool need_swab;
     55};
     56
     57/* The chip reads 16bits of data at time and place them directly into (little endian) CPU register.
     58 * So, the chip expects bytes order to be "B1 B0 B3 B2" (while LE is "B0 B1 B2 B3" and BE is
     59 * "B3 B2 B1 B0")
     60 *
     61 * A little endian host with bits_per_word == 16 should do the right job natively. The code below to
     62 * support big endian host and commonly used SPI 8bits.
     63 */
     64static int wfx_spi_copy_from_io(void *priv, unsigned int addr, void *dst, size_t count)
     65{
     66	struct wfx_spi_priv *bus = priv;
     67	u16 regaddr = (addr << 12) | (count / 2) | SET_READ;
     68	struct spi_message m;
     69	struct spi_transfer t_addr = {
     70		.tx_buf = &regaddr,
     71		.len = sizeof(regaddr),
     72	};
     73	struct spi_transfer t_msg = {
     74		.rx_buf = dst,
     75		.len = count,
     76	};
     77	u16 *dst16 = dst;
     78	int ret, i;
     79
     80	WARN(count % 2, "buffer size must be a multiple of 2");
     81
     82	cpu_to_le16s(&regaddr);
     83	if (bus->need_swab)
     84		swab16s(&regaddr);
     85
     86	spi_message_init(&m);
     87	spi_message_add_tail(&t_addr, &m);
     88	spi_message_add_tail(&t_msg, &m);
     89	ret = spi_sync(bus->func, &m);
     90
     91	if (bus->need_swab && addr == WFX_REG_CONFIG)
     92		for (i = 0; i < count / 2; i++)
     93			swab16s(&dst16[i]);
     94	return ret;
     95}
     96
     97static int wfx_spi_copy_to_io(void *priv, unsigned int addr, const void *src, size_t count)
     98{
     99	struct wfx_spi_priv *bus = priv;
    100	u16 regaddr = (addr << 12) | (count / 2);
    101	/* FIXME: use a bounce buffer */
    102	u16 *src16 = (void *)src;
    103	int ret, i;
    104	struct spi_message m;
    105	struct spi_transfer t_addr = {
    106		.tx_buf = &regaddr,
    107		.len = sizeof(regaddr),
    108	};
    109	struct spi_transfer t_msg = {
    110		.tx_buf = src,
    111		.len = count,
    112	};
    113
    114	WARN(count % 2, "buffer size must be a multiple of 2");
    115	WARN(regaddr & SET_READ, "bad addr or size overflow");
    116
    117	cpu_to_le16s(&regaddr);
    118
    119	/* Register address and CONFIG content always use 16bit big endian
    120	 * ("BADC" order)
    121	 */
    122	if (bus->need_swab)
    123		swab16s(&regaddr);
    124	if (bus->need_swab && addr == WFX_REG_CONFIG)
    125		for (i = 0; i < count / 2; i++)
    126			swab16s(&src16[i]);
    127
    128	spi_message_init(&m);
    129	spi_message_add_tail(&t_addr, &m);
    130	spi_message_add_tail(&t_msg, &m);
    131	ret = spi_sync(bus->func, &m);
    132
    133	if (bus->need_swab && addr == WFX_REG_CONFIG)
    134		for (i = 0; i < count / 2; i++)
    135			swab16s(&src16[i]);
    136	return ret;
    137}
    138
    139static void wfx_spi_lock(void *priv)
    140{
    141}
    142
    143static void wfx_spi_unlock(void *priv)
    144{
    145}
    146
    147static irqreturn_t wfx_spi_irq_handler(int irq, void *priv)
    148{
    149	struct wfx_spi_priv *bus = priv;
    150
    151	wfx_bh_request_rx(bus->core);
    152	return IRQ_HANDLED;
    153}
    154
    155static int wfx_spi_irq_subscribe(void *priv)
    156{
    157	struct wfx_spi_priv *bus = priv;
    158	u32 flags;
    159
    160	flags = irq_get_trigger_type(bus->func->irq);
    161	if (!flags)
    162		flags = IRQF_TRIGGER_HIGH;
    163	flags |= IRQF_ONESHOT;
    164	return devm_request_threaded_irq(&bus->func->dev, bus->func->irq, NULL,
    165					 wfx_spi_irq_handler, flags, "wfx", bus);
    166}
    167
    168static int wfx_spi_irq_unsubscribe(void *priv)
    169{
    170	struct wfx_spi_priv *bus = priv;
    171
    172	devm_free_irq(&bus->func->dev, bus->func->irq, bus);
    173	return 0;
    174}
    175
    176static size_t wfx_spi_align_size(void *priv, size_t size)
    177{
    178	/* Most of SPI controllers avoid DMA if buffer size is not 32bit aligned */
    179	return ALIGN(size, 4);
    180}
    181
    182static const struct wfx_hwbus_ops wfx_spi_hwbus_ops = {
    183	.copy_from_io    = wfx_spi_copy_from_io,
    184	.copy_to_io      = wfx_spi_copy_to_io,
    185	.irq_subscribe   = wfx_spi_irq_subscribe,
    186	.irq_unsubscribe = wfx_spi_irq_unsubscribe,
    187	.lock            = wfx_spi_lock,
    188	.unlock          = wfx_spi_unlock,
    189	.align_size      = wfx_spi_align_size,
    190};
    191
    192static int wfx_spi_probe(struct spi_device *func)
    193{
    194	struct wfx_platform_data *pdata;
    195	struct wfx_spi_priv *bus;
    196	int ret;
    197
    198	if (!func->bits_per_word)
    199		func->bits_per_word = 16;
    200	ret = spi_setup(func);
    201	if (ret)
    202		return ret;
    203	pdata = (struct wfx_platform_data *)spi_get_device_id(func)->driver_data;
    204	if (!pdata) {
    205		dev_err(&func->dev, "unable to retrieve driver data (please report)\n");
    206		return -ENODEV;
    207	}
    208
    209	/* Trace below is also displayed by spi_setup() if compiled with DEBUG */
    210	dev_dbg(&func->dev, "SPI params: CS=%d, mode=%d bits/word=%d speed=%d\n",
    211		func->chip_select, func->mode, func->bits_per_word, func->max_speed_hz);
    212	if (func->bits_per_word != 16 && func->bits_per_word != 8)
    213		dev_warn(&func->dev, "unusual bits/word value: %d\n", func->bits_per_word);
    214	if (func->max_speed_hz > 50000000)
    215		dev_warn(&func->dev, "%dHz is a very high speed\n", func->max_speed_hz);
    216
    217	bus = devm_kzalloc(&func->dev, sizeof(*bus), GFP_KERNEL);
    218	if (!bus)
    219		return -ENOMEM;
    220	bus->func = func;
    221	if (func->bits_per_word == 8 || IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
    222		bus->need_swab = true;
    223	spi_set_drvdata(func, bus);
    224
    225	bus->gpio_reset = devm_gpiod_get_optional(&func->dev, "reset", GPIOD_OUT_LOW);
    226	if (IS_ERR(bus->gpio_reset))
    227		return PTR_ERR(bus->gpio_reset);
    228	if (!bus->gpio_reset) {
    229		dev_warn(&func->dev, "gpio reset is not defined, trying to load firmware anyway\n");
    230	} else {
    231		gpiod_set_consumer_name(bus->gpio_reset, "wfx reset");
    232		gpiod_set_value_cansleep(bus->gpio_reset, 1);
    233		usleep_range(100, 150);
    234		gpiod_set_value_cansleep(bus->gpio_reset, 0);
    235		usleep_range(2000, 2500);
    236	}
    237
    238	bus->core = wfx_init_common(&func->dev, pdata, &wfx_spi_hwbus_ops, bus);
    239	if (!bus->core)
    240		return -EIO;
    241
    242	return wfx_probe(bus->core);
    243}
    244
    245static void wfx_spi_remove(struct spi_device *func)
    246{
    247	struct wfx_spi_priv *bus = spi_get_drvdata(func);
    248
    249	wfx_release(bus->core);
    250}
    251
    252/* For dynamic driver binding, kernel does not use OF to match driver. It only
    253 * use modalias and modalias is a copy of 'compatible' DT node with vendor
    254 * stripped.
    255 */
    256static const struct spi_device_id wfx_spi_id[] = {
    257	{ "wf200",    (kernel_ulong_t)&pdata_wf200 },
    258	{ "brd4001a", (kernel_ulong_t)&pdata_brd4001a },
    259	{ "brd8022a", (kernel_ulong_t)&pdata_brd8022a },
    260	{ "brd8023a", (kernel_ulong_t)&pdata_brd8023a },
    261	{ },
    262};
    263MODULE_DEVICE_TABLE(spi, wfx_spi_id);
    264
    265#ifdef CONFIG_OF
    266static const struct of_device_id wfx_spi_of_match[] = {
    267	{ .compatible = "silabs,wf200" },
    268	{ .compatible = "silabs,brd4001a" },
    269	{ .compatible = "silabs,brd8022a" },
    270	{ .compatible = "silabs,brd8023a" },
    271	{ },
    272};
    273MODULE_DEVICE_TABLE(of, wfx_spi_of_match);
    274#endif
    275
    276struct spi_driver wfx_spi_driver = {
    277	.driver = {
    278		.name = "wfx-spi",
    279		.of_match_table = of_match_ptr(wfx_spi_of_match),
    280	},
    281	.id_table = wfx_spi_id,
    282	.probe = wfx_spi_probe,
    283	.remove = wfx_spi_remove,
    284};