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

mmp_spi.c (4146B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * linux/drivers/video/mmp/hw/mmp_spi.c
      4 * using the spi in LCD controler for commands send
      5 *
      6 * Copyright (C) 2012 Marvell Technology Group Ltd.
      7 * Authors:  Guoqing Li <ligq@marvell.com>
      8 *          Lisa Du <cldu@marvell.com>
      9 *          Zhou Zhu <zzhu3@marvell.com>
     10 */
     11#include <linux/errno.h>
     12#include <linux/delay.h>
     13#include <linux/err.h>
     14#include <linux/io.h>
     15#include <linux/spi/spi.h>
     16#include "mmp_ctrl.h"
     17
     18/**
     19 * spi_write - write command to the SPI port
     20 * @spi:  the SPI device.
     21 * @data: can be 8/16/32-bit, MSB justified data to write.
     22 *
     23 * Wait bus transfer complete IRQ.
     24 * The caller is expected to perform the necessary locking.
     25 *
     26 * Returns:
     27 *   %-ETIMEDOUT	timeout occurred
     28 *   0			success
     29 */
     30static inline int lcd_spi_write(struct spi_device *spi, u32 data)
     31{
     32	int timeout = 100000, isr, ret = 0;
     33	u32 tmp;
     34	void __iomem *reg_base = (void __iomem *)
     35		*(void **)spi_master_get_devdata(spi->master);
     36
     37	/* clear ISR */
     38	writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
     39
     40	switch (spi->bits_per_word) {
     41	case 8:
     42		writel_relaxed((u8)data, reg_base + LCD_SPU_SPI_TXDATA);
     43		break;
     44	case 16:
     45		writel_relaxed((u16)data, reg_base + LCD_SPU_SPI_TXDATA);
     46		break;
     47	case 32:
     48		writel_relaxed((u32)data, reg_base + LCD_SPU_SPI_TXDATA);
     49		break;
     50	default:
     51		dev_err(&spi->dev, "Wrong spi bit length\n");
     52	}
     53
     54	/* SPI start to send command */
     55	tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
     56	tmp &= ~CFG_SPI_START_MASK;
     57	tmp |= CFG_SPI_START(1);
     58	writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
     59
     60	isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
     61	while (!(isr & SPI_IRQ_ENA_MASK)) {
     62		udelay(100);
     63		isr = readl_relaxed(reg_base + SPU_IRQ_ISR);
     64		if (!--timeout) {
     65			ret = -ETIMEDOUT;
     66			dev_err(&spi->dev, "spi cmd send time out\n");
     67			break;
     68		}
     69	}
     70
     71	tmp = readl_relaxed(reg_base + LCD_SPU_SPI_CTRL);
     72	tmp &= ~CFG_SPI_START_MASK;
     73	tmp |= CFG_SPI_START(0);
     74	writel_relaxed(tmp, reg_base + LCD_SPU_SPI_CTRL);
     75
     76	writel_relaxed(~SPI_IRQ_MASK, reg_base + SPU_IRQ_ISR);
     77
     78	return ret;
     79}
     80
     81static int lcd_spi_setup(struct spi_device *spi)
     82{
     83	void __iomem *reg_base = (void __iomem *)
     84		*(void **)spi_master_get_devdata(spi->master);
     85	u32 tmp;
     86
     87	tmp = CFG_SCLKCNT(16) |
     88		CFG_TXBITS(spi->bits_per_word) |
     89		CFG_SPI_SEL(1) | CFG_SPI_ENA(1) |
     90		CFG_SPI_3W4WB(1);
     91	writel(tmp, reg_base + LCD_SPU_SPI_CTRL);
     92
     93	/*
     94	 * After set mode it need a time to pull up the spi singals,
     95	 * or it would cause the wrong waveform when send spi command,
     96	 * especially on pxa910h
     97	 */
     98	tmp = readl_relaxed(reg_base + SPU_IOPAD_CONTROL);
     99	if ((tmp & CFG_IOPADMODE_MASK) != IOPAD_DUMB18SPI)
    100		writel_relaxed(IOPAD_DUMB18SPI |
    101			(tmp & ~CFG_IOPADMODE_MASK),
    102			reg_base + SPU_IOPAD_CONTROL);
    103	udelay(20);
    104	return 0;
    105}
    106
    107static int lcd_spi_one_transfer(struct spi_device *spi, struct spi_message *m)
    108{
    109	struct spi_transfer *t;
    110	int i;
    111
    112	list_for_each_entry(t, &m->transfers, transfer_list) {
    113		switch (spi->bits_per_word) {
    114		case 8:
    115			for (i = 0; i < t->len; i++)
    116				lcd_spi_write(spi, ((u8 *)t->tx_buf)[i]);
    117			break;
    118		case 16:
    119			for (i = 0; i < t->len/2; i++)
    120				lcd_spi_write(spi, ((u16 *)t->tx_buf)[i]);
    121			break;
    122		case 32:
    123			for (i = 0; i < t->len/4; i++)
    124				lcd_spi_write(spi, ((u32 *)t->tx_buf)[i]);
    125			break;
    126		default:
    127			dev_err(&spi->dev, "Wrong spi bit length\n");
    128		}
    129	}
    130
    131	m->status = 0;
    132	if (m->complete)
    133		m->complete(m->context);
    134	return 0;
    135}
    136
    137int lcd_spi_register(struct mmphw_ctrl *ctrl)
    138{
    139	struct spi_master *master;
    140	void **p_regbase;
    141	int err;
    142
    143	master = spi_alloc_master(ctrl->dev, sizeof(void *));
    144	if (!master) {
    145		dev_err(ctrl->dev, "unable to allocate SPI master\n");
    146		return -ENOMEM;
    147	}
    148	p_regbase = spi_master_get_devdata(master);
    149	*p_regbase = (void __force *)ctrl->reg_base;
    150
    151	/* set bus num to 5 to avoid conflict with other spi hosts */
    152	master->bus_num = 5;
    153	master->num_chipselect = 1;
    154	master->setup = lcd_spi_setup;
    155	master->transfer = lcd_spi_one_transfer;
    156
    157	err = spi_register_master(master);
    158	if (err < 0) {
    159		dev_err(ctrl->dev, "unable to register SPI master\n");
    160		spi_master_put(master);
    161		return err;
    162	}
    163
    164	dev_info(&master->dev, "registered\n");
    165
    166	return 0;
    167}